Lexicon updated to come from comfy_cozy

This commit is contained in:
Alexander G. Morano
2025-05-04 23:48:55 -04:00
parent ca52e98b6c
commit 2baba1e4c2
19 changed files with 882 additions and 1157 deletions
+7
View File
@@ -0,0 +1,7 @@
from enum import Enum
class EnumFillOperation(Enum):
DEFAULT = 0
FILL_ZERO = 20
FILL_ALL = 10
+58 -59
View File
@@ -12,6 +12,9 @@ from cozy_comfyui import \
InputType, EnumConvertType, \
deep_merge, parse_param, zip_longest_fill
from cozy_comfyui.lexicon import \
Lexicon
from cozy_comfyui.node import \
COZY_TYPE_ANY, \
CozyBaseNode
@@ -61,47 +64,46 @@ A timer and frame counter, emitting pulses or signals based on time intervals. I
d = deep_merge(d, {
"optional": {
# data to pass on a pulse of the loop
"TRIGGER": (COZY_TYPE_ANY, {
Lexicon.TRIGGER: (COZY_TYPE_ANY, {
"default": None,
"tooltip":"Output to send when beat (BPM setting) is hit"
"tooltip": "Output to send when beat (BPM setting) is hit"
}),
# forces a MOD on CYCLE
"VALUE": ("INT", {
Lexicon.VALUE: ("INT", {
"default": 0, "min": 0, "max": sys.maxsize,
"tooltip": "the current frame number of the tick"
"tooltip": "Current frame number of the tick"
}),
"LOOP": ("INT", {
Lexicon.LOOP: ("INT", {
"default": 0, "min": 0, "max": sys.maxsize,
"tooltip": "number of frames before looping starts. 0 means continuous playback (no loop point)"
"tooltip": "Number of frames before looping starts. 0 means continuous playback (no loop point)"
}),
"FPS": ("INT", {
"default": 24, "min": 1,
"tooltip": "Fixed frame step rate based on FPS (1/FPS)"
Lexicon.FPS: ("INT", {
"default": 24, "min": 1
}),
"BPM": ("INT", {
Lexicon.BPM: ("INT", {
"default": 120, "min": 1, "max": 60000,
"tooltip": "BPM trigger rate to send the input. If input is empty, TRUE is sent on trigger"
}),
"NOTE": ("INT", {
Lexicon.NOTE: ("INT", {
"default": 4, "min": 1, "max": 256,
"tooltip":"Number of beats per measure. Quarter note is 4, Eighth is 8, 16 is 16, etc."}),
"tooltip": "Number of beats per measure. Quarter note is 4, Eighth is 8, 16 is 16, etc."}),
# stick the current "count"
"HOLD": ("BOOLEAN", {
Lexicon.HOLD: ("BOOLEAN", {
"default": False}),
# manual total = 0
"RESET": ("BOOLEAN", {
Lexicon.RESET: ("BOOLEAN", {
"default": False}),
# how many frames to dump....
"BATCH": ("INT", {
Lexicon.BATCH: ("INT", {
"default": 1, "min": 1, "max": 32767,
"tooltip": "Number of frames wanted"
}),
"STEP": ("INT", {
Lexicon.STEP: ("INT", {
"default": 0, "min": 0, "max": sys.maxsize
}),
}
})
return d
return Lexicon._parse(d)
def __init__(self, *arg, **kw) -> None:
super().__init__(*arg, **kw)
@@ -109,21 +111,21 @@ A timer and frame counter, emitting pulses or signals based on time intervals. I
self.__frame = 0
def run(self, ident, **kw) -> tuple[int, float, float, Any]:
passthru = parse_param(kw, "TRIGGER", EnumConvertType.ANY, None)[0]
stride = parse_param(kw, "STEP", EnumConvertType.INT, 0, 0, sys.maxsize)[0]
loop = parse_param(kw, "LOOP", EnumConvertType.INT, 0, 0, sys.maxsize)[0]
self.__frame = parse_param(kw, "VALUE", EnumConvertType.INT, self.__frame, 0, sys.maxsize)[0]
passthru = parse_param(kw, Lexicon.TRIGGER, EnumConvertType.ANY, None)[0]
stride = parse_param(kw, Lexicon.STEP, EnumConvertType.INT, 0, 0, sys.maxsize)[0]
loop = parse_param(kw, Lexicon.LOOP, EnumConvertType.INT, 0, 0, sys.maxsize)[0]
self.__frame = parse_param(kw, Lexicon.VALUE, EnumConvertType.INT, self.__frame, 0, sys.maxsize)[0]
if loop != 0:
self.__frame %= loop
# start_frame = max(0, start_frame)
hold = parse_param(kw, "HOLD", EnumConvertType.BOOLEAN, False)[0]
fps = parse_param(kw, "FPS", EnumConvertType.INT, 24, 1)[0]
bpm = parse_param(kw, "BPM", EnumConvertType.INT, 120, 1)[0]
divisor = parse_param(kw, "NOTE", EnumConvertType.INT, 4, 1)[0]
hold = parse_param(kw, Lexicon.HOLD, EnumConvertType.BOOLEAN, False)[0]
fps = parse_param(kw, Lexicon.FPS, EnumConvertType.INT, 24, 1)[0]
bpm = parse_param(kw, Lexicon.BPM, EnumConvertType.INT, 120, 1)[0]
divisor = parse_param(kw, Lexicon.NOTE, EnumConvertType.INT, 4, 1)[0]
beat = 60. / max(1., bpm) / divisor
batch = parse_param(kw, "BATCH", EnumConvertType.INT, 1, 1)[0]
batch = parse_param(kw, Lexicon.BATCH, EnumConvertType.INT, 1, 1)[0]
step_fps = 1. / max(1., float(fps))
reset = parse_param(kw, "RESET", EnumConvertType.BOOLEAN, False)[0]
reset = parse_param(kw, Lexicon.RESET, EnumConvertType.BOOLEAN, False)[0]
if loop == 0 and (parse_reset(ident) > 0 or reset):
self.__frame = 0
trigger = None
@@ -172,33 +174,33 @@ Value generator with normalized values based on based on time interval.
d = deep_merge(d, {
"optional": {
# forces a MOD on CYCLE
"VALUE": ("INT", {
Lexicon.VALUE: ("INT", {
"default": 0, "min": -sys.maxsize, "max": sys.maxsize,
"tooltip": "Starting value of the tick"
}),
# interval between frames
"STEP": ("FLOAT", {
Lexicon.STEP: ("FLOAT", {
"default": 0, "min": -sys.maxsize, "max": sys.maxsize, "precision": 3,
"tooltip": "Amount to add to each frame per tick"
}),
"LOOP": ("INT", {
Lexicon.LOOP: ("INT", {
"default": 0, "min": -sys.maxsize, "max": sys.maxsize,
"tooltip": "What value before looping starts. 0 means linear playback (no loop point)"
}),
# how many frames to dump....
"BATCH": ("INT", {
Lexicon.BATCH: ("INT", {
"default": 1, "min": 1, "max": 1500,
"tooltip": "Total frames wanted"
}),
}
})
return d
return Lexicon._parse(d)
def run(self, **kw) -> tuple[int, float|int]:
value = parse_param(kw, "VALUE", EnumConvertType.INT, 0, -sys.maxsize, sys.maxsize)[0]
step = parse_param(kw, "STEP", EnumConvertType.FLOAT, 0, -sys.maxsize, sys.maxsize)[0]
loop = parse_param(kw, "LOOP", EnumConvertType.INT, 0, -sys.maxsize, sys.maxsize)[0]
batch = parse_param(kw, "BATCH", EnumConvertType.INT, 1, 1, 1500)[0]
value = parse_param(kw, Lexicon.VALUE, EnumConvertType.INT, 0, -sys.maxsize, sys.maxsize)[0]
step = parse_param(kw, Lexicon.STEP, EnumConvertType.FLOAT, 0, -sys.maxsize, sys.maxsize)[0]
loop = parse_param(kw, Lexicon.LOOP, EnumConvertType.INT, 0, -sys.maxsize, sys.maxsize)[0]
batch = parse_param(kw, Lexicon.BATCH, EnumConvertType.INT, 1, 1, 1500)[0]
if loop == 0:
loop = batch
@@ -230,38 +232,35 @@ Produce waveforms like sine, square, or sawtooth with adjustable frequency, ampl
d = super().INPUT_TYPES()
d = deep_merge(d, {
"optional": {
"WAVE": (EnumWave._member_names_, {
Lexicon.WAVE: (EnumWave._member_names_, {
"default": EnumWave.SIN.name}),
"FREQ": ("FLOAT", {
"default": 1, "min": 0, "max": sys.maxsize, "step": 0.01,
"tooltip": "Frequency"}),
"AMP": ("FLOAT", {
"default": 1, "min": 0, "max": sys.maxsize, "step": 0.01,
"tooltip": "Amplitude"}),
"PHASE": ("FLOAT", {
Lexicon.FREQ: ("FLOAT", {
"default": 1, "min": 0, "max": sys.maxsize, "step": 0.01,}),
Lexicon.AMP: ("FLOAT", {
"default": 1, "min": 0, "max": sys.maxsize, "step": 0.01,}),
Lexicon.PHASE: ("FLOAT", {
"default": 0, "min": 0.0, "max": 1.0, "step": 0.01}),
"OFFSET": ("FLOAT", {
Lexicon.OFFSET: ("FLOAT", {
"default": 0, "min": 0.0, "max": 1.0, "step": 0.001}),
"TIME": ("FLOAT", {
Lexicon.TIME: ("FLOAT", {
"default": 0, "min": 0, "max": sys.maxsize, "step": 0.0001}),
"INVERT": ("BOOLEAN", {
Lexicon.INVERT: ("BOOLEAN", {
"default": False}),
"ABSOLUTE": ("BOOLEAN", {
"default": False,
"tooltips": "Return the absolute value of the input"}),
Lexicon.ABSOLUTE: ("BOOLEAN", {
"default": False,}),
}
})
return d
return Lexicon._parse(d)
def run(self, **kw) -> tuple[float, int]:
op = parse_param(kw, "WAVE", EnumWave, EnumWave.SIN.name)
freq = parse_param(kw, "FREQ", EnumConvertType.FLOAT, 1., 0.000001, sys.maxsize)
amp = parse_param(kw, "AMP", EnumConvertType.FLOAT, 1., 0., sys.maxsize)
phase = parse_param(kw, "PHASE", EnumConvertType.FLOAT, 0.)
shift = parse_param(kw, "OFFSET", EnumConvertType.FLOAT, 0.)
delta_time = parse_param(kw, "TIME", EnumConvertType.FLOAT, 0., 0., sys.maxsize)
invert = parse_param(kw, "INVERT", EnumConvertType.BOOLEAN, False)
absolute = parse_param(kw, "ABSOLUTE", EnumConvertType.BOOLEAN, False)
op = parse_param(kw, Lexicon.WAVE, EnumWave, EnumWave.SIN.name)
freq = parse_param(kw, Lexicon.FREQ, EnumConvertType.FLOAT, 1., 0.000001, sys.maxsize)
amp = parse_param(kw, Lexicon.AMP, EnumConvertType.FLOAT, 1., 0., sys.maxsize)
phase = parse_param(kw, Lexicon.PHASE, EnumConvertType.FLOAT, 0.)
shift = parse_param(kw, Lexicon.OFFSET, EnumConvertType.FLOAT, 0.)
delta_time = parse_param(kw, Lexicon.TIME, EnumConvertType.FLOAT, 0., 0., sys.maxsize)
invert = parse_param(kw, Lexicon.INVERT, EnumConvertType.BOOLEAN, False)
absolute = parse_param(kw, Lexicon.ABSOLUTE, EnumConvertType.BOOLEAN, False)
results = []
params = list(zip_longest_fill(op, freq, amp, phase, shift, delta_time, invert, absolute))
pbar = ProgressBar(len(params))
+158 -177
View File
@@ -8,7 +8,6 @@ from typing import Any, List
from collections import Counter
import torch
import numpy as np
from scipy.special import gamma
from comfy.utils import ProgressBar
@@ -18,10 +17,16 @@ from cozy_comfyui import \
TensorType, InputType, EnumConvertType, \
deep_merge, parse_dynamic, parse_param, parse_value, zip_longest_fill
from cozy_comfyui.lexicon import \
Lexicon
from cozy_comfyui.node import \
COZY_TYPE_ANY, COZY_TYPE_NUMERICAL, COZY_TYPE_FULL, \
CozyBaseNode
from . import \
EnumFillOperation
from ..sup.anim import \
EnumEase, \
ease_op
@@ -233,17 +238,22 @@ IMAGE and MASK will return a TRUE bit for any non-black pixel, as a stream of bi
d = super().INPUT_TYPES()
d = deep_merge(d, {
"optional": {
"VALUE": (COZY_TYPE_FULL, {"default": None, "tooltip":"the value to convert into bits"}),
"BITS": ("INT", {"default": 8, "min": 1, "max": 64, "tooltip":"number of output bits requested"}),
"MSB": ("BOOLEAN", {"default": False, "tooltip":"return the most signifigant bits (True) or least signifigant bits first"})
Lexicon.VALUE: (COZY_TYPE_FULL, {
"default": None,
"tooltip": "Value to convert into bits"}),
Lexicon.BIT: ("INT", {
"default": 8, "min": 1, "max": 64,
"tooltip": "Number of output bits requested"}),
Lexicon.MSB: ("BOOLEAN", {
"default": False})
}
})
return d
return Lexicon._parse(d)
def run(self, **kw) -> tuple[List[int], List[bool]]:
value = parse_param(kw, "VALUE", EnumConvertType.ANY, 0)
bits = parse_param(kw, "BITS", EnumConvertType.INT, 8, 1, 64)
msb = parse_param(kw, "MSB", EnumConvertType.INT, False)
value = parse_param(kw, Lexicon.VALUE, EnumConvertType.ANY, 0)
bits = parse_param(kw, Lexicon.BIT, EnumConvertType.INT, 8, 1, 64)
msb = parse_param(kw, Lexicon.MSB, EnumConvertType.INT, False)
params = list(zip_longest_fill(value, bits))
pbar = ProgressBar(len(params))
results = []
@@ -288,45 +298,44 @@ Evaluates two inputs (A and B) with a specified comparison operators and optiona
d = super().INPUT_TYPES()
d = deep_merge(d, {
"optional": {
"A": (COZY_TYPE_FULL, {
Lexicon.IN_A: (COZY_TYPE_FULL, {
"default": 0,
"tooltip":"First value to compare"}),
"B": (COZY_TYPE_FULL, {
Lexicon.IN_B: (COZY_TYPE_FULL, {
"default": 0,
"tooltip":"Second value to compare"}),
"PASS": (COZY_TYPE_ANY, {
Lexicon.SUCCESS: (COZY_TYPE_ANY, {
"default": 0,
"tooltip": "Passed to OUT on a successful condition"}),
"FAIL": (COZY_TYPE_ANY, {
"tooltip": "Sent to OUT on a successful condition"}),
Lexicon.FAIL: (COZY_TYPE_ANY, {
"default": 0,
"tooltip": "Passed to OUT on a failure condition"}),
"COMPARE": (EnumComparison._member_names_, {
"tooltip": "Sent to OUT on a failure condition"}),
Lexicon.FUNCTION: (EnumComparison._member_names_, {
"default": EnumComparison.EQUAL.name,
"tooltip": "Comparison function. Sends the data in PASS on successful comparison to OUT, otherwise sends the value in FAIL"}),
"FLIP": ("BOOLEAN", {
Lexicon.SWAP: ("BOOLEAN", {
"default": False,}),
Lexicon.INVERT: ("BOOLEAN", {
"default": False,
"tooltip": "Reverse the inputs A and B"}),
"INVERT": ("BOOLEAN", {
"default": False,
"tooltip": "Reverse the successful and failure inputs"}),
"tooltip": "Reverse the PASS and FAIL inputs"}),
}
})
return d
return Lexicon._parse(d)
def run(self, **kw) -> tuple[Any, Any]:
A = parse_param(kw, "A", EnumConvertType.ANY, 0)
B = parse_param(kw, "B", EnumConvertType.ANY, 0)
size = max(len(A), len(B))
good = parse_param(kw, "PASS", EnumConvertType.ANY, 0)[:size]
fail = parse_param(kw, "FAIL", EnumConvertType.ANY, 0)[:size]
op = parse_param(kw, "COMPARE", EnumComparison, EnumComparison.EQUAL.name)[:size]
flip = parse_param(kw, "FLIP", EnumConvertType.BOOLEAN, False)[:size]
invert = parse_param(kw, "INVERT", EnumConvertType.BOOLEAN, False)[:size]
params = list(zip_longest_fill(A, B, good, fail, op, flip, invert))
in_a = parse_param(kw, Lexicon.IN_A, EnumConvertType.ANY, 0)
in_b = parse_param(kw, Lexicon.IN_B, EnumConvertType.ANY, 0)
size = max(len(in_a), len(in_b))
good = parse_param(kw, Lexicon.SUCCESS, EnumConvertType.ANY, 0)[:size]
fail = parse_param(kw, Lexicon.FAIL, EnumConvertType.ANY, 0)[:size]
op = parse_param(kw, Lexicon.FUNCTION, EnumComparison, EnumComparison.EQUAL.name)[:size]
swap = parse_param(kw, Lexicon.SWAP, EnumConvertType.BOOLEAN, False)[:size]
invert = parse_param(kw, Lexicon.INVERT, EnumConvertType.BOOLEAN, False)[:size]
params = list(zip_longest_fill(in_a, in_b, good, fail, op, swap, invert))
pbar = ProgressBar(len(params))
vals = []
results = []
for idx, (A, B, good, fail, op, flip, invert) in enumerate(params):
for idx, (A, B, good, fail, op, swap, invert) in enumerate(params):
if not isinstance(A, (tuple, list,)):
A = [A]
if not isinstance(B, (tuple, list,)):
@@ -343,7 +352,7 @@ Evaluates two inputs (A and B) with a specified comparison operators and optiona
if not isinstance(val_b, (list,)):
val_b = [val_b]
if flip:
if swap:
val_a, val_b = val_b, val_a
match op:
@@ -406,7 +415,7 @@ class LerpNode(CozyBaseNode):
NAME = "LERP (JOV) 🔰"
CATEGORY = JOV_CATEGORY
RETURN_TYPES = (COZY_TYPE_ANY,)
RETURN_NAMES = ("🦄",)
RETURN_NAMES = ("❔",)
OUTPUT_IS_LIST = (True,)
OUTPUT_TOOLTIPS = (
f"Output can vary depending on the type chosen in the {"TYPE"} parameter"
@@ -426,47 +435,40 @@ Additionally, you can specify the easing function (EASE) and the desired output
names_convert = EnumConvertType._member_names_[:6]
d = deep_merge(d, {
"optional": {
"A": (COZY_TYPE_FULL, {
"tooltip": "Custom Start Point"
}),
"B": (COZY_TYPE_FULL, {
"tooltip": "Custom End Point"
}),
"ALPHA": ("VEC4", {
"default": (0.5, 0.5, 0.5, 0.5), "mij": 0., "maj": 1.0,
"tooltip": "Blend Amount. 0 = full A, 1 = full B"
}),
"AA": ("VEC4", {
"default": (0, 0, 0, 0),
"tooltip":"default value vector for A"
}),
"BB": ("VEC4", {
"default": (1,1,1,1),
"tooltip":"default value vector for B"
}),
"TYPE": (names_convert, {
Lexicon.IN_A: (COZY_TYPE_FULL, {
"tooltip": "Custom Start Point"}),
Lexicon.IN_B: (COZY_TYPE_FULL, {
"tooltip": "Custom End Point"}),
Lexicon.ALPHA: ("VEC4", {
"default": (0.5, 0.5, 0.5, 0.5), "mij": 0., "maj": 1.0,}),
Lexicon.TYPE: (names_convert, {
"default": "FLOAT",
"tooltip":"Output type desired from resultant operation"
}),
"EASE": (["NONE"] + EnumEase._member_names_, {
"default": "NONE"
}),
"tooltip": "Output type desired from resultant operation"}),
Lexicon.EASE: (["NONE"] + EnumEase._member_names_, {
"default": "NONE"}),
Lexicon.DEFAULT_A: ("VEC4", {
"default": (0, 0, 0, 0)}),
Lexicon.DEFAULT_B: ("VEC4", {
"default": (1,1,1,1)}),
Lexicon.FILL: (EnumFillOperation._member_names_, {
"default": EnumFillOperation.DEFAULT.name}),
}
})
return d
return Lexicon._parse(d)
def run(self, **kw) -> tuple[Any, Any]:
A = parse_param(kw, "A", EnumConvertType.ANY, 0)
B = parse_param(kw, "B", EnumConvertType.ANY, 0)
a_xyzw = parse_param(kw, "AA", EnumConvertType.VEC4, (0, 0, 0, 0))
b_xyzw = parse_param(kw, "BB", EnumConvertType.VEC4, (1, 1, 1, 1))
alpha = parse_param(kw, "FLOAT",EnumConvertType.VEC4, (0.5,0.5,0.5,0.5), 0, 1)
op = parse_param(kw, "EASE", EnumEase, EnumEase.SIN_IN_OUT.name)
typ = parse_param(kw, "TYPE", EnumNumberType, EnumNumberType.FLOAT.name)
A = parse_param(kw, Lexicon.IN_A, EnumConvertType.ANY, 0)
B = parse_param(kw, Lexicon.IN_B, EnumConvertType.ANY, 0)
alpha = parse_param(kw, Lexicon.ALPHA,EnumConvertType.VEC4, (0.5,0.5,0.5,0.5), 0, 1)
typ = parse_param(kw, Lexicon.TYPE, EnumNumberType, EnumNumberType.FLOAT.name)
op = parse_param(kw, Lexicon.EASE, EnumEase, EnumEase.SIN_IN_OUT.name)
a_xyzw = parse_param(kw, Lexicon.DEFAULT_A, EnumConvertType.VEC4, (0, 0, 0, 0))
b_xyzw = parse_param(kw, Lexicon.DEFAULT_B, EnumConvertType.VEC4, (1, 1, 1, 1))
fill = parse_param(kw, Lexicon.FILL, EnumConvertType.BOOLEAN, False)
values = []
params = list(zip_longest_fill(A, B, a_xyzw, b_xyzw, alpha, op, typ))
params = list(zip_longest_fill(A, B, alpha, typ, op, a_xyzw, b_xyzw, fill,))
pbar = ProgressBar(len(params))
for idx, (A, B, a_xyzw, b_xyzw, alpha, op, typ) in enumerate(params):
for idx, (A, B, alpha, typ, op, a_xyzw, b_xyzw, fill,) in enumerate(params):
size = int(typ.value / 10)
if A is None:
@@ -528,39 +530,36 @@ Perform single function operations like absolute value, mean, median, mode, magn
typ = EnumConvertType._member_names_[:6]
d = deep_merge(d, {
"optional": {
"A": (COZY_TYPE_NUMERICAL, {
Lexicon.IN_A: (COZY_TYPE_NUMERICAL, {
"default": None}),
"FUNCTION": (EnumUnaryOperation._member_names_, {
Lexicon.FUNCTION: (EnumUnaryOperation._member_names_, {
"default": EnumUnaryOperation.ABS.name}),
"TYPE": (typ, {
"default": EnumConvertType.FLOAT.name,
"tooltip":"Take the input and convert it into the selected type"}),
"FILL": ("BOOLEAN", {
"default": False,
"tooltip":"If the value should fill the output type (VEC*)"}),
Lexicon.TYPE: (typ, {
"default": EnumConvertType.FLOAT.name,}),
Lexicon.DEFAULT_A: ("VEC4", {
"default": (0,0,0,0),
"label": ["X", "Y", "Z", "W"]}),
Lexicon.FILL: (EnumFillOperation._member_names_, {
"default": EnumFillOperation.DEFAULT.name}),
}
})
return d
return Lexicon._parse(d)
def run(self, **kw) -> tuple[bool]:
results = []
A = parse_param(kw, "A", EnumConvertType.ANY, 0)
op = parse_param(kw, "FUNCTION", EnumUnaryOperation, EnumUnaryOperation.ABS.name)
out = parse_param(kw, "TYPE", EnumConvertType, EnumConvertType.FLOAT.name)
fill = parse_param(kw, "FILL", EnumConvertType.BOOLEAN, False)
params = list(zip_longest_fill(A, op, out, fill))
A = parse_param(kw, Lexicon.IN_A, EnumConvertType.ANY, 0)
op = parse_param(kw, Lexicon.FUNCTION, EnumUnaryOperation, EnumUnaryOperation.ABS.name)
out = parse_param(kw, Lexicon.TYPE, EnumConvertType, EnumConvertType.FLOAT.name)
a_xyzw = parse_param(kw, Lexicon.DEFAULT_A, EnumConvertType.VEC4, (0, 0, 0, 0))
fill = parse_param(kw, Lexicon.FILL, EnumConvertType.BOOLEAN, False)
params = list(zip_longest_fill(A, op, out, a_xyzw, fill))
pbar = ProgressBar(len(params))
for idx, (A, op, out, fill) in enumerate(params):
typ = EnumConvertType.FLOAT
if isinstance(A, (bool, )):
typ = EnumConvertType.BOOLEAN
elif isinstance(A, (list, set, tuple,)):
typ = EnumConvertType(len(A) * 10)
val = parse_value(A, typ, 0)
if not isinstance(val, (list, tuple, )):
val = [val]
val = [float(v) for v in val]
for idx, (A, op, out, a_xyzw, fill) in enumerate(params):
size = min(3, max(0 if not isinstance(A, (list,)) else len(A)))
best_type = [EnumConvertType.FLOAT, EnumConvertType.VEC2, EnumConvertType.VEC3, EnumConvertType.VEC4][size]
val = parse_value(A, best_type, a_xyzw)
val = parse_value(val, EnumConvertType.VEC4, a_xyzw)
# val = [float(v) for v in val]
match op:
case EnumUnaryOperation.MEAN:
val = [sum(val) / len(val)]
@@ -626,62 +625,57 @@ Execute binary operations like addition, subtraction, multiplication, division,
d = super().INPUT_TYPES()
d = deep_merge(d, {
"optional": {
"A": (COZY_TYPE_NUMERICAL, {
"default": None,
"tooltip":"Passes a raw value directly, or supplies defaults for any value inputs without connections"}),
"B": (COZY_TYPE_NUMERICAL, {
"default": None,
"tooltip":"Passes a raw value directly, or supplies defaults for any value inputs without connections"}),
"FUNCTION": (EnumBinaryOperation._member_names_, {
"default": EnumBinaryOperation.ADD.name,
"tooltip":"Arithmetic operation to perform"}),
"TYPE": (names_convert, {
Lexicon.IN_A: (COZY_TYPE_NUMERICAL, {
"default": None}),
Lexicon.IN_B: (COZY_TYPE_NUMERICAL, {
"default": None}),
Lexicon.FUNCTION: (EnumBinaryOperation._member_names_, {
"default": EnumBinaryOperation.ADD.name,}),
Lexicon.TYPE: (names_convert, {
"default": names_convert[2],
"tooltip":"Output type desired from resultant operation"}),
"FLIP": ("BOOLEAN", {
Lexicon.SWAP: ("BOOLEAN", {
"default": False}),
"AA": ("VEC4", {
Lexicon.DEFAULT_A: ("VEC4", {
"default": (0,0,0,0),
"label": ["X", "Y", "Z", "W"],
"tooltip":"value vector"}),
"BB": ("VEC4", {
"label": ["X", "Y", "Z", "W"]}),
Lexicon.DEFAULT_B: ("VEC4", {
"default": (0,0,0,0),
"label": ["X", "Y", "Z", "W"],
"tooltip":"value vector"}),
"label": ["X", "Y", "Z", "W"]}),
Lexicon.FILL: (EnumFillOperation._member_names_, {
"default": EnumFillOperation.DEFAULT.name}),
}
})
return d
return Lexicon._parse(d)
def run(self, **kw) -> tuple[bool]:
results = []
A = parse_param(kw, "A", EnumConvertType.ANY, None)
B = parse_param(kw, "B", EnumConvertType.ANY, None)
a_xyzw = parse_param(kw, "AA", EnumConvertType.VEC4, (0, 0, 0, 0))
b_xyzw = parse_param(kw, "BB", EnumConvertType.VEC4, (0, 0, 0, 0))
op = parse_param(kw, "FUNCTION", EnumBinaryOperation, EnumBinaryOperation.ADD.name)
typ = parse_param(kw, "TYPE", EnumConvertType, EnumConvertType.FLOAT.name)
flip = parse_param(kw, "FLIP", EnumConvertType.BOOLEAN, False)
params = list(zip_longest_fill(A, B, a_xyzw, b_xyzw, op, typ, flip))
A = parse_param(kw, Lexicon.IN_A, EnumConvertType.ANY, None)
B = parse_param(kw, Lexicon.IN_B, EnumConvertType.ANY, None)
op = parse_param(kw, Lexicon.FUNCTION, EnumBinaryOperation, EnumBinaryOperation.ADD.name)
typ = parse_param(kw, Lexicon.TYPE, EnumConvertType, EnumConvertType.FLOAT.name)
swap = parse_param(kw, Lexicon.SWAP, EnumConvertType.BOOLEAN, False)
a_xyzw = parse_param(kw, Lexicon.DEFAULT_A, EnumConvertType.VEC4, (0, 0, 0, 0))
b_xyzw = parse_param(kw, Lexicon.DEFAULT_B, EnumConvertType.VEC4, (0, 0, 0, 0))
fill = parse_param(kw, Lexicon.FILL, EnumConvertType.BOOLEAN, False)
params = list(zip_longest_fill(A, B, a_xyzw, b_xyzw, op, typ, swap, fill))
pbar = ProgressBar(len(params))
for idx, (A, B, a_xyzw, b_xyzw, op, typ, flip) in enumerate(params):
for idx, (A, B, a_xyzw, b_xyzw, op, typ, swap, fill) in enumerate(params):
size = min(3, max(0 if not isinstance(A, (list,)) else len(A), 0 if not isinstance(B, (list,)) else len(B)))
best_type = [EnumConvertType.FLOAT, EnumConvertType.VEC2, EnumConvertType.VEC3, EnumConvertType.VEC4][size]
print(type(A), type(B), A, B, a_xyzw)
val_a = parse_value(A, best_type, a_xyzw)
print(val_a)
return
val_a = parse_value(val_a, EnumConvertType.VEC4, a_xyzw)
val_b = parse_value(B, best_type, b_xyzw)
val_b = parse_value(val_b, EnumConvertType.VEC4, b_xyzw)
print(val_a, val_b)
#val_a = parse_value(A, EnumConvertType.VEC4, A if A is not None else a_xyzw)
#val_b = parse_value(B, EnumConvertType.VEC4, B if B is not None else b_xyzw)
if flip:
if swap:
val_a, val_b = val_b, val_a
#size = max(1, int(typ.value / 10))
size = max(1, int(typ.value / 10))
val_a = val_a[:size+1]
val_b = val_b[:size+1]
@@ -756,10 +750,11 @@ Execute binary operations like addition, subtraction, multiplication, division,
default = val
if len(val) == 0:
default = [0]
val = parse_value(val, typ, default)
results.append(val)
pbar.update_absolute(idx)
return results
return (results,)
class StringerNode(CozyBaseNode):
NAME = "STRINGER (JOV) 🪀"
@@ -778,34 +773,32 @@ Manipulate strings through filtering
d = deep_merge(d, {
"optional": {
# split, join, replace, trim/lift
"FUNCTION": (EnumConvertString._member_names_, {
"default": EnumConvertString.SPLIT.name,
"tooltip":"Operation to perform on the input string"}),
"KEY": ("STRING", {
Lexicon.FUNCTION: (EnumConvertString._member_names_, {
"default": EnumConvertString.SPLIT.name}),
Lexicon.KEY: ("STRING", {
"default":"", "dynamicPrompt":False,
"tooltip":"Delimiter (SPLIT/JOIN) or string to use as search string (FIND/REPLACE)."}),
"REPLACE": ("STRING", {
"tooltip": "Delimiter (SPLIT/JOIN) or string to use as search string (FIND/REPLACE)."}),
Lexicon.REPLACE: ("STRING", {
"default":"", "dynamicPrompt":False}),
"RANGE": ("VEC3", {
Lexicon.RANGE: ("VEC3", {
"default":(0, -1, 1), "int": True,
"tooltip":"Start, End and Step. Values will clip to the actual list size(s)."}),
"tooltip": "Start, End and Step. Values will clip to the actual list size(s)."}),
}
})
return d
return Lexicon._parse(d)
def run(self, **kw) -> tuple[TensorType, ...]:
# turn any all inputs into the
data_list = parse_dynamic(kw, "STRING", EnumConvertType.ANY, "")
data_list = parse_dynamic(kw, Lexicon.STRING, EnumConvertType.ANY, "")
if data_list is None:
logger.warn("no data for list")
return ([], 0)
op = parse_param(kw, "FUNCTION", EnumConvertString, EnumConvertString.SPLIT.name)[0]
key = parse_param(kw, "KEY", EnumConvertType.STRING, "")[0]
replace = parse_param(kw, "REPLACE", EnumConvertType.STRING, "")[0]
stenst = parse_param(kw, "RANGE", EnumConvertType.VEC3INT, (0, -1, 1))[0]
op = parse_param(kw, Lexicon.FUNCTION, EnumConvertString, EnumConvertString.SPLIT.name)[0]
key = parse_param(kw, Lexicon.KEY, EnumConvertType.STRING, "")[0]
replace = parse_param(kw, Lexicon.REPLACE, EnumConvertType.STRING, "")[0]
stenst = parse_param(kw, Lexicon.RANGE, EnumConvertType.VEC3INT, (0, -1, 1))[0]
results = []
print(data_list)
match op:
case EnumConvertString.SPLIT:
results = data_list
@@ -837,7 +830,7 @@ class SwizzleNode(CozyBaseNode):
NAME = "SWIZZLE (JOV) 😵"
CATEGORY = JOV_CATEGORY
RETURN_TYPES = (COZY_TYPE_ANY,)
RETURN_NAMES = ("🦄",)
RETURN_NAMES = ("❔",)
OUTPUT_IS_LIST = (True,)
SORT = 40
DESCRIPTION = """
@@ -850,44 +843,32 @@ Swap components between two vectors based on specified swizzle patterns and valu
names_convert = EnumConvertType._member_names_[3:6]
d = deep_merge(d, {
"optional": {
"A": (COZY_TYPE_NUMERICAL, {}),
"B": (COZY_TYPE_NUMERICAL, {}),
"TYPE": (names_convert, {
"default": names_convert[2],
"tooltip":"Output type desired from resultant operation"
}),
"SWAP_X": (EnumSwizzle._member_names_, {
"default": EnumSwizzle.A_X.name,
"tooltip": "Replace input Red channel with target channel or constant"
}),
"SWAP_Y": (EnumSwizzle._member_names_, {
"default": EnumSwizzle.A_Y.name,
"tooltip": "Replace input Green channel with target channel or constant"
}),
"SWAP_Z": (EnumSwizzle._member_names_, {
"default": EnumSwizzle.A_Z.name,
"tooltip": "Replace input Blue channel with target channel or constant"
}),
"SWAP_W": (EnumSwizzle._member_names_, {
"default": EnumSwizzle.A_W.name,
"tooltip": "Replace input W channel with target channel or constant"
}),
"VEC": ("VEC4", {
"default": (0,0,0,0), "mij": -sys.maxsize, "maj": sys.maxsize,
"tooltip": "Default values for missing channels"
})
Lexicon.IN_A: (COZY_TYPE_NUMERICAL, {}),
Lexicon.IN_B: (COZY_TYPE_NUMERICAL, {}),
Lexicon.TYPE: (names_convert, {
"default": names_convert[2]}),
Lexicon.SWAP_X: (EnumSwizzle._member_names_, {
"default": EnumSwizzle.A_X.name,}),
Lexicon.SWAP_Y: (EnumSwizzle._member_names_, {
"default": EnumSwizzle.A_Y.name,}),
Lexicon.SWAP_Z: (EnumSwizzle._member_names_, {
"default": EnumSwizzle.A_Z.name,}),
Lexicon.SWAP_W: (EnumSwizzle._member_names_, {
"default": EnumSwizzle.A_W.name,}),
Lexicon.DEFAULT: ("VEC4", {
"default": (0,0,0,0), "mij": -sys.maxsize, "maj": sys.maxsize})
}
})
return d
return Lexicon._parse(d)
def run(self, **kw) -> tuple[TensorType, ...]:
pA = parse_param(kw, "A", EnumConvertType.VEC4, (0,0,0,0))
pB = parse_param(kw, "B", EnumConvertType.VEC4, (0,0,0,0))
swap_x = parse_param(kw, "SWAP_X", EnumSwizzle, EnumSwizzle.A_X.name)
swap_y = parse_param(kw, "SWAP_Y", EnumSwizzle, EnumSwizzle.A_Y.name)
swap_z = parse_param(kw, "SWAP_Z", EnumSwizzle, EnumSwizzle.A_W.name)
swap_w = parse_param(kw, "SWAP_W", EnumSwizzle, EnumSwizzle.A_Z.name)
default = parse_param(kw, "VEC", EnumConvertType.VEC4, 0, -sys.maxsize, sys.maxsize)
pA = parse_param(kw, Lexicon.IN_A, EnumConvertType.VEC4, (0,0,0,0))
pB = parse_param(kw, Lexicon.IN_B, EnumConvertType.VEC4, (0,0,0,0))
swap_x = parse_param(kw, Lexicon.SWAP_X, EnumSwizzle, EnumSwizzle.A_X.name)
swap_y = parse_param(kw, Lexicon.SWAP_Y, EnumSwizzle, EnumSwizzle.A_Y.name)
swap_z = parse_param(kw, Lexicon.SWAP_Z, EnumSwizzle, EnumSwizzle.A_W.name)
swap_w = parse_param(kw, Lexicon.SWAP_W, EnumSwizzle, EnumSwizzle.A_Z.name)
default = parse_param(kw, Lexicon.DEFAULT, EnumConvertType.VEC4, 0, -sys.maxsize, sys.maxsize)
params = list(zip_longest_fill(pA, pB, swap_x, x, swap_y, y, swap_z, z, swap_w, w))
results = []
+95 -129
View File
@@ -13,6 +13,9 @@ from cozy_comfyui import \
InputType, RGBAMaskType, EnumConvertType, TensorType, \
deep_merge, parse_param, zip_longest_fill
from cozy_comfyui.lexicon import \
Lexicon
from cozy_comfyui.node import \
COZY_TYPE_IMAGE, \
CozyBaseNode, CozyImageNode
@@ -72,30 +75,22 @@ Simulate color blindness effects on images. You can select various types of colo
d = super().INPUT_TYPES()
d = deep_merge(d, {
"optional": {
"IMAGE": (COZY_TYPE_IMAGE, {
"tooltip": "Pixel Data (RGBA, RGB or Grayscale)"
}),
"DEFICIENCY": (EnumCBDeficiency._member_names_, {
"default": EnumCBDeficiency.PROTAN.name,
"tooltip": "Type of color deficiency: Red (Protanopia), Green (Deuteranopia), Blue (Tritanopia)"
}),
"SIMULATOR": (EnumCBSimulator._member_names_, {
"default": EnumCBSimulator.AUTOSELECT.name,
"tooltip": "Solver to use when translating to new color space"
}),
"VAL": ("FLOAT", {
"default": 1, "min": 0, "max": 1, "step": 0.001,
"tooltip": "alpha blending"
}),
Lexicon.IMAGE: (COZY_TYPE_IMAGE, {}),
Lexicon.DEFICIENCY: (EnumCBDeficiency._member_names_, {
"default": EnumCBDeficiency.PROTAN.name,}),
Lexicon.SOLVER: (EnumCBSimulator._member_names_, {
"default": EnumCBSimulator.AUTOSELECT.name,}),
Lexicon.ALPHA: ("FLOAT", {
"default": 1, "min": 0, "max": 1, "step": 0.001,}),
}
})
return d
return Lexicon._parse(d)
def run(self, **kw) -> RGBAMaskType:
pA = parse_param(kw, "IMAGE", EnumConvertType.IMAGE, None)
deficiency = parse_param(kw, "DEFICIENCY", EnumCBDeficiency, EnumCBDeficiency.PROTAN.name)
simulator = parse_param(kw, "SIMULATOR", EnumCBSimulator, EnumCBSimulator.AUTOSELECT.name)
severity = parse_param(kw, "VAL", EnumConvertType.FLOAT, 1)
pA = parse_param(kw, Lexicon.IMAGE, EnumConvertType.IMAGE, None)
deficiency = parse_param(kw, Lexicon.DEFICIENCY, EnumCBDeficiency, EnumCBDeficiency.PROTAN.name)
simulator = parse_param(kw, Lexicon.SOLVER, EnumCBSimulator, EnumCBSimulator.AUTOSELECT.name)
severity = parse_param(kw, Lexicon.VALUE, EnumConvertType.FLOAT, 1)
params = list(zip_longest_fill(pA, deficiency, simulator, severity))
images = []
pbar = ProgressBar(len(params))
@@ -118,55 +113,43 @@ Adjust the color scheme of one image to match another with the Color Match Node.
d = super().INPUT_TYPES()
d = deep_merge(d, {
"optional": {
"SOURCE": (COZY_TYPE_IMAGE, {
"tooltip": "Pixel Data (RGBA, RGB or Grayscale)"
}),
"TARGET": (COZY_TYPE_IMAGE, {
"tooltip": "Pixel Data (RGBA, RGB or Grayscale)"
}),
"MODE": (EnumColorMatchMode._member_names_, {
Lexicon.IMAGE_SOURCE: (COZY_TYPE_IMAGE, {}),
Lexicon.IMAGE_TARGET: (COZY_TYPE_IMAGE, {}),
Lexicon.MODE: (EnumColorMatchMode._member_names_, {
"default": EnumColorMatchMode.REINHARD.name,
"tooltip": "Match colors from an image or built-in (LUT), Histogram lookups or Reinhard method"
}),
"MAP": (EnumColorMatchMap._member_names_, {
"default": EnumColorMatchMap.USER_MAP.name,
"tooltip": "Custom image that will be transformed into a LUT or a built-in cv2 LUT"
}),
"COLORMAP": (EnumColorMap._member_names_, {
"default": EnumColorMap.HSV.name,
"tooltip": "One of two dozen CV2 Built-in Colormap LUT (Look Up Table) Presets"
}),
"VAL": ("INT", {
"tooltip": "Match colors from an image or built-in (LUT), Histogram lookups or Reinhard method"}),
Lexicon.MAP: (EnumColorMatchMap._member_names_, {
"default": EnumColorMatchMap.USER_MAP.name, }),
Lexicon.COLORMAP: (EnumColorMap._member_names_, {
"default": EnumColorMap.HSV.name,}),
Lexicon.VALUE: ("INT", {
"default": 255, "min": 0, "max": 255,
"tooltip":"The number of colors to use from the LUT during the remap. Will quantize the LUT range."}),
"FLIP": ("BOOLEAN", {
"default": False,
"tooltip": "Flip the SOURCE and TARGET inputs"}),
"INVERT": ("BOOLEAN", {
"default": False,
"tooltip": "Invert the color match output"}),
"MATTE": ("VEC4", {
"default": (0, 0, 0, 255), "rgb": True,
"tooltip": "Background Color"}),
Lexicon.SWAP: ("BOOLEAN", {
"default": False,}),
Lexicon.INVERT: ("BOOLEAN", {
"default": False,}),
Lexicon.MATTE: ("VEC4", {
"default": (0, 0, 0, 255), "rgb": True,}),
}
})
return d
return Lexicon._parse(d)
def run(self, **kw) -> RGBAMaskType:
pA = parse_param(kw, "SOURCE", EnumConvertType.IMAGE, None)
pB = parse_param(kw, "TARGET", EnumConvertType.IMAGE, None)
colormatch_mode = parse_param(kw, "MODE", EnumColorMatchMode, EnumColorMatchMode.REINHARD.name)
colormatch_map = parse_param(kw, f"MAP", EnumColorMatchMap, EnumColorMatchMap.USER_MAP.name)
colormap = parse_param(kw, "COLORMAP", EnumColorMap, EnumColorMap.HSV.name)
num_colors = parse_param(kw, "VAL", EnumConvertType.INT, 255)
flip = parse_param(kw, "FLIP", EnumConvertType.BOOLEAN, False)
invert = parse_param(kw, "INVERT", EnumConvertType.BOOLEAN, False)
matte = parse_param(kw, "MATTE", EnumConvertType.VEC4, (0, 0, 0, 255), 0, 255)
params = list(zip_longest_fill(pA, pB, colormap, colormatch_mode, colormatch_map, num_colors, flip, invert, matte))
pA = parse_param(kw, Lexicon.IMAGE_SOURCE, EnumConvertType.IMAGE, None)
pB = parse_param(kw, Lexicon.IMAGE_TARGET, EnumConvertType.IMAGE, None)
mode = parse_param(kw, Lexicon.MODE, EnumColorMatchMode, EnumColorMatchMode.REINHARD.name)
cmap = parse_param(kw, Lexicon.MAP, EnumColorMatchMap, EnumColorMatchMap.USER_MAP.name)
colormap = parse_param(kw, Lexicon.COLORMAP, EnumColorMap, EnumColorMap.HSV.name)
num_colors = parse_param(kw, Lexicon.VALUE, EnumConvertType.INT, 255)
swap = parse_param(kw, Lexicon.SWAP, EnumConvertType.BOOLEAN, False)
invert = parse_param(kw, Lexicon.INVERT, EnumConvertType.BOOLEAN, False)
matte = parse_param(kw, Lexicon.MATTE, EnumConvertType.VEC4, (0, 0, 0, 255), 0, 255)
params = list(zip_longest_fill(pA, pB, mode, cmap, colormap, num_colors, swap, invert, matte))
images = []
pbar = ProgressBar(len(params))
for idx, (pA, pB, colormap, mode, cmap, num_colors, flip, invert, matte) in enumerate(params):
if flip == True:
for idx, (pA, pB, mode, cmap, colormap, num_colors, swap, invert, matte) in enumerate(params):
if swap == True:
pA, pB = pB, pA
mask = None
@@ -223,35 +206,30 @@ The top-k colors ordered from most->least used as a strip, tonal palette and 3D
d = super().INPUT_TYPES()
d = deep_merge(d, {
"optional": {
"IMAGE": (COZY_TYPE_IMAGE, {
"tooltip": "Pixel Data (RGBA, RGB or Grayscale)"
}),
"VAL": ("INT", {
Lexicon.IMAGE: (COZY_TYPE_IMAGE, {}),
Lexicon.VALUE: ("INT", {
"default": 12, "min": 1, "max": 255,
"tooltip":"The top K colors to select."
}),
"SIZE": ("INT", {
"tooltip": "The top K colors to select"}),
Lexicon.SIZE: ("INT", {
"default": 32, "min": 1, "max": 256,
"tooltip":"Height of the tones in the strip. Width is based on input."
}),
"COUNT": ("INT", {
"tooltip": "Height of the tones in the strip. Width is based on input"}),
Lexicon.COUNT: ("INT", {
"default": 33, "min": 3, "max": 256,
"tooltip":"Number of nodes to use in interpolation of full LUT (256 is every pixel)."
}),
"WH": ("VEC2", {
"tooltip": "Number of nodes to use in interpolation of full LUT (256 is every pixel)"}),
Lexicon.WH: ("VEC2", {
"default": (256, 256), "mij":IMAGE_SIZE_MIN, "int": True,
"label": ["W", "H"]
}),
}
})
return d
return Lexicon._parse(d)
def run(self, **kw) -> RGBAMaskType:
pA = parse_param(kw, "IMAGE", EnumConvertType.IMAGE, None)
kcolors = parse_param(kw, "VAL", EnumConvertType.INT, 12, 1, 255)
lut_height = parse_param(kw, "SIZE", EnumConvertType.INT, 32, 1, 256)
nodes = parse_param(kw, "COUNT", EnumConvertType.INT, 33, 1, 255)
wihi = parse_param(kw, "WH", EnumConvertType.VEC2INT, (256, 256), IMAGE_SIZE_MIN)
pA = parse_param(kw, Lexicon.IMAGE, EnumConvertType.IMAGE, None)
kcolors = parse_param(kw, Lexicon.VALUE, EnumConvertType.INT, 12, 1, 255)
lut_height = parse_param(kw, Lexicon.SIZE, EnumConvertType.INT, 32, 1, 256)
nodes = parse_param(kw, Lexicon.COUNT, EnumConvertType.INT, 33, 1, 255)
wihi = parse_param(kw, Lexicon.WH, EnumConvertType.VEC2INT, (256, 256), IMAGE_SIZE_MIN)
params = list(zip_longest_fill(pA, kcolors, nodes, lut_height, wihi))
top_colors = []
@@ -299,27 +277,23 @@ Users can customize the angle of separation for color calculations, offering fle
d = super().INPUT_TYPES()
d = deep_merge(d, {
"optional": {
"IMAGE": (COZY_TYPE_IMAGE, {
"tooltip": "Pixel Data (RGBA, RGB or Grayscale)"
}),
"SCHEME": (EnumColorTheory._member_names_, {
"default": EnumColorTheory.COMPLIMENTARY.name
}),
"VAL": ("INT", {
Lexicon.IMAGE: (COZY_TYPE_IMAGE, {}),
Lexicon.SCHEME: (EnumColorTheory._member_names_, {
"default": EnumColorTheory.COMPLIMENTARY.name}),
Lexicon.VALUE: ("INT", {
"default": 45, "min": -90, "max": 90,
"tooltip": "Custom angle of separation to use when calculating colors"
}),
"INVERT": ("BOOLEAN", {
"tooltip": "Custom angle of separation to use when calculating colors"}),
Lexicon.INVERT: ("BOOLEAN", {
"default": False})
}
})
return d
return Lexicon._parse(d)
def run(self, **kw) -> tuple[List[TensorType], List[TensorType]]:
pA = parse_param(kw, "IMAGE", EnumConvertType.IMAGE, None)
scheme = parse_param(kw, "SCHEME", EnumColorTheory, EnumColorTheory.COMPLIMENTARY.name)
user = parse_param(kw, "VAL", EnumConvertType.INT, 0, -180, 180)
invert = parse_param(kw, "INVERT", EnumConvertType.BOOLEAN, False)
pA = parse_param(kw, Lexicon.IMAGE, EnumConvertType.IMAGE, None)
scheme = parse_param(kw, Lexicon.SCHEME, EnumColorTheory, EnumColorTheory.COMPLIMENTARY.name)
user = parse_param(kw, Lexicon.VALUE, EnumConvertType.INT, 0, -180, 180)
invert = parse_param(kw, Lexicon.INVERT, EnumConvertType.BOOLEAN, False)
params = list(zip_longest_fill(pA, scheme, user, invert))
images = []
pbar = ProgressBar(len(params))
@@ -347,48 +321,38 @@ The gradient image will be translated into a single row lookup table.
d = super().INPUT_TYPES()
d = deep_merge(d, {
"optional": {
"IMAGE": (COZY_TYPE_IMAGE, {
"tooltip":"Image to remap with gradient input"
}),
"GRADIENT": (COZY_TYPE_IMAGE, {
"tooltip":f"Look up table (LUT) to remap the input image in `{"IMAGE"}`"
}),
"FLIP": ("BOOLEAN", {
"default":False,
"tooltip":"Reverse the gradient from left-to-right "
}),
"MODE": (EnumScaleMode._member_names_, {
"default": EnumScaleMode.MATTE.name,
"tooltip": "If the image should be resized to fit within given dimensions or keep the original size"
}),
"WH": ("VEC2", {
Lexicon.IMAGE: (COZY_TYPE_IMAGE, {
"tooltip": "Image to remap with gradient input"}),
Lexicon.GRADIENT: (COZY_TYPE_IMAGE, {
"tooltip": f"Look up table (LUT) to remap the input image in `{"IMAGE"}`"}),
Lexicon.REVERSE: ("BOOLEAN", {
"default": False,
"tooltip": "Reverse the gradient from left-to-right"}),
Lexicon.MODE: (EnumScaleMode._member_names_, {
"default": EnumScaleMode.MATTE.name,}),
Lexicon.WH: ("VEC2", {
"default": (512, 512), "mij":IMAGE_SIZE_MIN, "int": True,
"label": ["W", "H"]
}),
"SAMPLE": (EnumInterpolation._member_names_, {
"default": EnumInterpolation.LANCZOS4.name,
"tooltip": "Sampling method for resizing images"
}),
"MATTE": ("VEC4", {
"default": (0, 0, 0, 255), "rgb": True,
"tooltip": "Background Color"
})
"label": ["W", "H"] }),
Lexicon.SAMPLE: (EnumInterpolation._member_names_, {
"default": EnumInterpolation.LANCZOS4.name,}),
Lexicon.MATTE: ("VEC4", {
"default": (0, 0, 0, 255), "rgb": True,})
}
})
return d
return Lexicon._parse(d)
def run(self, **kw) -> RGBAMaskType:
pA = parse_param(kw, "IMAGE", EnumConvertType.IMAGE, None)
gradient = parse_param(kw, "GRADIENT", EnumConvertType.IMAGE, None)
flip = parse_param(kw, "FLIP", EnumConvertType.BOOLEAN, False)
mode = parse_param(kw, "MODE", EnumScaleMode, EnumScaleMode.MATTE.name)
wihi = parse_param(kw, "WH", EnumConvertType.VEC2INT, (512, 512), IMAGE_SIZE_MIN)
sample = parse_param(kw, "SAMPLE", EnumInterpolation, EnumInterpolation.LANCZOS4.name)
matte = parse_param(kw, "MATTE", EnumConvertType.VEC4INT, (0, 0, 0, 255), 0, 255)
pA = parse_param(kw, Lexicon.IMAGE, EnumConvertType.IMAGE, None)
gradient = parse_param(kw, Lexicon.GRADIENT, EnumConvertType.IMAGE, None)
reverse = parse_param(kw, Lexicon.REVERSE, EnumConvertType.BOOLEAN, False)
mode = parse_param(kw, Lexicon.MODE, EnumScaleMode, EnumScaleMode.MATTE.name)
wihi = parse_param(kw, Lexicon.WH, EnumConvertType.VEC2INT, (512, 512), IMAGE_SIZE_MIN)
sample = parse_param(kw, Lexicon.SAMPLE, EnumInterpolation, EnumInterpolation.LANCZOS4.name)
matte = parse_param(kw, Lexicon.MATTE, EnumConvertType.VEC4INT, (0, 0, 0, 255), 0, 255)
images = []
params = list(zip_longest_fill(pA, gradient, flip, mode, sample, wihi, matte))
params = list(zip_longest_fill(pA, gradient, reverse, mode, sample, wihi, matte))
pbar = ProgressBar(len(params))
for idx, (pA, gradient, flip, mode, sample, wihi, matte) in enumerate(params):
for idx, (pA, gradient, reverse, mode, sample, wihi, matte) in enumerate(params):
pA = channel_solid(chan=EnumImageType.BGR) if pA is None else tensor_to_cv(pA)
mask = None
if pA.ndim == 3 and pA.shape[2] == 4:
@@ -399,8 +363,10 @@ The gradient image will be translated into a single row lookup table.
if mode != EnumScaleMode.MATTE:
w, h = wihi
pA = image_scalefit(pA, w, h, mode, sample)
if mask is not None:
pA = image_mask_add(pA, mask)
images.append(cv_to_tensor_full(pA, matte))
pbar.update_absolute(idx)
return image_stack(images)
+144 -189
View File
@@ -10,6 +10,9 @@ from cozy_comfyui import \
InputType, RGBAMaskType, EnumConvertType, \
deep_merge, parse_param, zip_longest_fill
from cozy_comfyui.lexicon import \
Lexicon
from cozy_comfyui.node import \
COZY_TYPE_IMAGE, \
CozyBaseNode, CozyImageNode
@@ -62,57 +65,49 @@ Advanced options include pixelation, quantization, and morphological operations
d = super().INPUT_TYPES()
d = deep_merge(d, {
"optional": {
"IMAGE": (COZY_TYPE_IMAGE, {
"tooltip": "Pixel Data (RGBA, RGB or Grayscale)"
}),
"MASK": (COZY_TYPE_IMAGE, {
"tooltip": "Pixel Data (RGBA, RGB or Grayscale)"
}),
"FUNCTION": (EnumAdjustOP._member_names_, {
"default": EnumAdjustOP.BLUR.name,
"tooltip":"Type of adjustment (e.g., blur, sharpen, invert)"}),
"RADIUS": ("INT", {
Lexicon.IMAGE: (COZY_TYPE_IMAGE, {}),
Lexicon.MASK: (COZY_TYPE_IMAGE, {}),
Lexicon.FUNCTION: (EnumAdjustOP._member_names_, {
"default": EnumAdjustOP.BLUR.name,}),
Lexicon.RADIUS: ("INT", {
"default": 3, "min": 3}),
"VAL": ("FLOAT", {
Lexicon.VALUE: ("FLOAT", {
"default": 1, "min": 0, "step": 0.01}),
"LoHi": ("VEC2", {
Lexicon.LOHI: ("VEC2", {
"default": (0, 1), "mij": 0, "maj": 1,
"label": ["Low", "HI"]}),
"LMH": ("VEC3", {
Lexicon.LMH: ("VEC3", {
"default": (0, 0.5, 1), "mij": 0, "maj": 1,
"label": ["Low", "MID", "HI"],
"tooltip": "Low, Middle, High"}),
"HSV": ("VEC3",{
"label": ["Low", "MID", "HI"],}),
Lexicon.HSV: ("VEC3",{
"default": (0, 1, 1), "mij": 0, "maj": 1,
"label": ["H", "S", "V"],
"tooltip": "Hue, Saturation and Value"}),
"CONTRAST": ("FLOAT", {
"label": ["H", "S", "V"],}),
Lexicon.CONTRAST: ("FLOAT", {
"default": 0, "min": 0, "max": 1, "step": 0.01}),
"GAMMA": ("FLOAT", {
Lexicon.GAMMA: ("FLOAT", {
"default": 1, "min": 0.00001, "max": 1, "step": 0.01}),
"MATTE": ("VEC4", {
"default": (0, 0, 0, 255), "rgb": True,
"tooltip": "Background Color"}),
"INVERT": ("BOOLEAN", {
Lexicon.MATTE: ("VEC4", {
"default": (0, 0, 0, 255), "rgb": True,}),
Lexicon.INVERT: ("BOOLEAN", {
"default": False,
"tooltip": "Invert the mask input"})
}
})
return d
return Lexicon._parse(d)
def run(self, **kw) -> RGBAMaskType:
pA = parse_param(kw, "IMAGE", EnumConvertType.IMAGE, None)
mask = parse_param(kw, "MASK", EnumConvertType.IMAGE, None)
op = parse_param(kw, "FUNCTION", EnumAdjustOP, EnumAdjustOP.BLUR.name)
radius = parse_param(kw, "RADIUS", EnumConvertType.INT, 3, 3)
val = parse_param(kw, "VAL", EnumConvertType.FLOAT, 0, 0)
lohi = parse_param(kw, "LoHi", EnumConvertType.VEC2, (0, 1), 0, 1)
lmh = parse_param(kw, "LMH", EnumConvertType.VEC3, (0, 0.5, 1), 0, 1)
hsv = parse_param(kw, "HSV", EnumConvertType.VEC3, (0, 1, 1), 0, 1)
contrast = parse_param(kw, "CONTRAST", EnumConvertType.FLOAT, 1, 0, 1)
gamma = parse_param(kw, "GAMMA", EnumConvertType.FLOAT, 1, 0, 1)
matte = parse_param(kw, "MATTE", EnumConvertType.VEC4INT, (0, 0, 0, 255), 0, 255)
invert = parse_param(kw, "INVERT", EnumConvertType.BOOLEAN, False)
pA = parse_param(kw, Lexicon.IMAGE, EnumConvertType.IMAGE, None)
mask = parse_param(kw, Lexicon.MASK, EnumConvertType.IMAGE, None)
op = parse_param(kw, Lexicon.FUNCTION, EnumAdjustOP, EnumAdjustOP.BLUR.name)
radius = parse_param(kw, Lexicon.RADIUS, EnumConvertType.INT, 3, 3)
val = parse_param(kw, Lexicon.VALUE, EnumConvertType.FLOAT, 0, 0)
lohi = parse_param(kw, Lexicon.LOHI, EnumConvertType.VEC2, (0, 1), 0, 1)
lmh = parse_param(kw, Lexicon.LMH, EnumConvertType.VEC3, (0, 0.5, 1), 0, 1)
hsv = parse_param(kw, Lexicon.HSV, EnumConvertType.VEC3, (0, 1, 1), 0, 1)
contrast = parse_param(kw, Lexicon.CONTRAST, EnumConvertType.FLOAT, 1, 0, 1)
gamma = parse_param(kw, Lexicon.GAMMA, EnumConvertType.FLOAT, 1, 0, 1)
matte = parse_param(kw, Lexicon.MATTE, EnumConvertType.VEC4INT, (0, 0, 0, 255), 0, 255)
invert = parse_param(kw, Lexicon.INVERT, EnumConvertType.BOOLEAN, False)
params = list(zip_longest_fill(pA, mask, op, radius, val, lohi,
lmh, hsv, contrast, gamma, matte, invert))
images = []
@@ -228,50 +223,43 @@ Combine two input images using various blending modes, such as normal, screen, m
d = super().INPUT_TYPES()
d = deep_merge(d, {
"optional": {
"IMAGE_A": (COZY_TYPE_IMAGE, {
"tooltip": "Background Plate"}),
"IMAGE_B": (COZY_TYPE_IMAGE, {
"tooltip": "Image to Overlay on Background Plate"}),
"MASK": (COZY_TYPE_IMAGE, {
Lexicon.IMAGE_BACK: (COZY_TYPE_IMAGE, {}),
Lexicon.IMAGE_FORE: (COZY_TYPE_IMAGE, {}),
Lexicon.MASK: (COZY_TYPE_IMAGE, {
"tooltip": "Optional Mask to use for Alpha Blend Operation. If empty, will use the ALPHA of B"}),
"FUNCTION": (EnumBlendType._member_names_, {
"default": EnumBlendType.NORMAL.name,
"tooltip": "Blending Operation"}),
"ALPHA": ("FLOAT", {
"default": 1, "min": 0, "max": 1, "step": 0.01,
"tooltip": "Amount of Blending to Perform on the Selected Operation"}),
"FLIP": ("BOOLEAN", {
Lexicon.FUNCTION: (EnumBlendType._member_names_, {
"default": EnumBlendType.NORMAL.name,}),
Lexicon.ALPHA: ("FLOAT", {
"default": 1, "min": 0, "max": 1, "step": 0.01,}),
Lexicon.FLIP: ("BOOLEAN", {
"default": False}),
"INVERT": ("BOOLEAN", {
Lexicon.INVERT: ("BOOLEAN", {
"default": False, "tooltip": "Invert the mask input"}),
"MODE": (EnumScaleMode._member_names_, {
"default": EnumScaleMode.MATTE.name,
"tooltip": "If the image should be resized to fit within given dimensions or keep the original size"}),
"WH": ("VEC2", {
Lexicon.MODE: (EnumScaleMode._member_names_, {
"default": EnumScaleMode.MATTE.name,}),
Lexicon.WH: ("VEC2", {
"default": (512, 512), "mij":IMAGE_SIZE_MIN, "int": True,
"label": ["W", "H"]}),
"SAMPLE": (EnumInterpolation._member_names_, {
"default": EnumInterpolation.LANCZOS4.name,
"tooltip": "Sampling method for resizing images"}),
"MATTE": ("VEC4", {
"default": (0, 0, 0, 255), "rgb": True,
"tooltip": "Background Color"})
Lexicon.SAMPLE: (EnumInterpolation._member_names_, {
"default": EnumInterpolation.LANCZOS4.name,}),
Lexicon.MATTE: ("VEC4", {
"default": (0, 0, 0, 255), "rgb": True,})
}
})
return d
return Lexicon._parse(d)
def run(self, **kw) -> RGBAMaskType:
pA = parse_param(kw, "IMAGE_A", EnumConvertType.IMAGE, None)
pB = parse_param(kw, "IMAGE_B", EnumConvertType.IMAGE, None)
mask = parse_param(kw, "MASK", EnumConvertType.MASK, None)
func = parse_param(kw, "FUNCTION", EnumBlendType, EnumBlendType.NORMAL.name)
alpha = parse_param(kw, "ALPHA", EnumConvertType.FLOAT, 1, 0, 1)
flip = parse_param(kw, "FLIP", EnumConvertType.BOOLEAN, False)
mode = parse_param(kw, "MODE", EnumScaleMode, EnumScaleMode.MATTE.name)
wihi = parse_param(kw, "WH", EnumConvertType.VEC2INT, (512, 512), IMAGE_SIZE_MIN)
sample = parse_param(kw, "SAMPLE", EnumInterpolation, EnumInterpolation.LANCZOS4.name)
matte = parse_param(kw, "MATTE", EnumConvertType.VEC4INT, (0, 0, 0, 255), 0, 255)
invert = parse_param(kw, "INVERT", EnumConvertType.BOOLEAN, False)
pA = parse_param(kw, Lexicon.IMAGE_BACK, EnumConvertType.IMAGE, None)
pB = parse_param(kw, Lexicon.IMAGE_FORE, EnumConvertType.IMAGE, None)
mask = parse_param(kw, Lexicon.MASK, EnumConvertType.MASK, None)
func = parse_param(kw, Lexicon.FUNCTION, EnumBlendType, EnumBlendType.NORMAL.name)
alpha = parse_param(kw, Lexicon.ALPHA, EnumConvertType.FLOAT, 1, 0, 1)
flip = parse_param(kw, Lexicon.FLIP, EnumConvertType.BOOLEAN, False)
mode = parse_param(kw, Lexicon.MODE, EnumScaleMode, EnumScaleMode.MATTE.name)
wihi = parse_param(kw, Lexicon.WH, EnumConvertType.VEC2INT, (512, 512), IMAGE_SIZE_MIN)
sample = parse_param(kw, Lexicon.SAMPLE, EnumInterpolation, EnumInterpolation.LANCZOS4.name)
matte = parse_param(kw, Lexicon.MATTE, EnumConvertType.VEC4INT, (0, 0, 0, 255), 0, 255)
invert = parse_param(kw, Lexicon.INVERT, EnumConvertType.BOOLEAN, False)
params = list(zip_longest_fill(pA, pB, mask, func, alpha, flip, mode, wihi, sample, matte, invert))
images = []
pbar = ProgressBar(len(params))
@@ -335,33 +323,29 @@ Create masks based on specific color ranges within an image. Specify the color r
d = super().INPUT_TYPES()
d = deep_merge(d, {
"optional": {
"IMAGE": (COZY_TYPE_IMAGE, {
"tooltip": "Pixel Data (RGBA, RGB or Grayscale)"
}),
"START": ("VEC3", {
Lexicon.IMAGE: (COZY_TYPE_IMAGE, {}),
Lexicon.START: ("VEC3", {
"default": (128, 128, 128), "rgb": True}),
"RANGE": ("BOOLEAN", {
Lexicon.RANGE: ("BOOLEAN", {
"default": False,
"tooltip": "use an end point (start->end) when calculating the filter range"}),
"END": ("VEC3", {
"tooltip": "Use an end point (start->end) when calculating the filter range"}),
Lexicon.END: ("VEC3", {
"default": (128, 128, 128), "rgb": True}),
"FUZZ": ("VEC3", {
"default": (0.5,0.5,0.5), "mij":0, "maj":1,
"tooltip": "the fuzziness use to extend the start and end range(s)"}),
"MATTE": ("VEC4", {
"default": (0, 0, 0, 255), "rgb": True,
"tooltip": "Background Color"}),
Lexicon.FUZZ: ("VEC3", {
"default": (0.5,0.5,0.5), "mij":0, "maj":1,}),
Lexicon.MATTE: ("VEC4", {
"default": (0, 0, 0, 255), "rgb": True,}),
}
})
return d
return Lexicon._parse(d)
def run(self, **kw) -> RGBAMaskType:
pA = parse_param(kw, "IMAGE", EnumConvertType.IMAGE, None)
start = parse_param(kw, "START", EnumConvertType.VEC3INT, (128,128,128), 0, 255)
use_range = parse_param(kw, "RANGE", EnumConvertType.BOOLEAN, False, 0, 255)
end = parse_param(kw, "END", EnumConvertType.VEC3INT, (128,128,128), 0, 255)
fuzz = parse_param(kw, "FUZZ", EnumConvertType.VEC3, (0.5,0.5,0.5), 0, 1)
matte = parse_param(kw, "MATTE", EnumConvertType.VEC4INT, (0, 0, 0, 255), 0, 255)
pA = parse_param(kw, Lexicon.IMAGE, EnumConvertType.IMAGE, None)
start = parse_param(kw, Lexicon.START, EnumConvertType.VEC3INT, (128,128,128), 0, 255)
use_range = parse_param(kw, Lexicon.RANGE, EnumConvertType.BOOLEAN, False, 0, 255)
end = parse_param(kw, Lexicon.END, EnumConvertType.VEC3INT, (128,128,128), 0, 255)
fuzz = parse_param(kw, Lexicon.FUZZ, EnumConvertType.VEC3, (0.5,0.5,0.5), 0, 1)
matte = parse_param(kw, Lexicon.MATTE, EnumConvertType.VEC4INT, (0, 0, 0, 255), 0, 255)
params = list(zip_longest_fill(pA, start, use_range, end, fuzz, matte))
images = []
pbar = ProgressBar(len(params))
@@ -390,56 +374,41 @@ Combines individual color channels (red, green, blue) along with an optional mas
d = super().INPUT_TYPES()
d = deep_merge(d, {
"optional": {
"IMAGE": (COZY_TYPE_IMAGE, {
"tooltip": "Pixel Data (RGBA, RGB or Grayscale)"
}),
"🟥": (COZY_TYPE_IMAGE, {
"tooltip": "Red"
}),
"🟩": (COZY_TYPE_IMAGE, {
"tooltip": "Green"
}),
"🟦": (COZY_TYPE_IMAGE, {
"tooltip": "Blue"
}),
"⬜": (COZY_TYPE_IMAGE, {
"tooltip": "Alpha"
}),
"MODE": (EnumScaleMode._member_names_, {
"default": EnumScaleMode.MATTE.name,
"tooltip": "If the image should be resized to fit within given dimensions or keep the original size"}),
"WH": ("VEC2", {
Lexicon.IMAGE: (COZY_TYPE_IMAGE, {}),
Lexicon.CHAN_RED: (COZY_TYPE_IMAGE, {}),
Lexicon.CHAN_GREEN: (COZY_TYPE_IMAGE, {}),
Lexicon.CHAN_BLUE: (COZY_TYPE_IMAGE, {}),
Lexicon.CHAN_ALPHA: (COZY_TYPE_IMAGE, {}),
Lexicon.MODE: (EnumScaleMode._member_names_, {
"default": EnumScaleMode.MATTE.name,}),
Lexicon.WH: ("VEC2", {
"default": (512, 512), "mij":IMAGE_SIZE_MIN, "int": True,
"label": ["W", "H"],
"tooltip": "Width and Height"}),
"SAMPLE": (EnumInterpolation._member_names_, {
"default": EnumInterpolation.LANCZOS4.name,
"tooltip": "Sampling method for resizing images"}),
"MATTE": ("VEC4", {
"default": (0, 0, 0, 255), "rgb": True,
"tooltip": "Background Color"}),
"FLIP": ("VEC4", {
"label": ["W", "H"],}),
Lexicon.SAMPLE: (EnumInterpolation._member_names_, {
"default": EnumInterpolation.LANCZOS4.name,}),
Lexicon.MATTE: ("VEC4", {
"default": (0, 0, 0, 255), "rgb": True,}),
Lexicon.FLIP: ("VEC4", {
"default": (0,0,0,0), "mij":0, "maj":1,
"tooltip": "Invert specific input prior to merging. R, G, B, A."}),
"INVERT": ("BOOLEAN", {
"default": False,
"tooltip": "Invert the final merged output"})
Lexicon.INVERT: ("BOOLEAN", {
"default": False,})
}
})
return d
return Lexicon._parse(d)
def run(self, **kw) -> RGBAMaskType:
rgba = parse_param(kw, "IMAGE", EnumConvertType.IMAGE, None)
R = parse_param(kw, "🟥", EnumConvertType.MASK, None)
G = parse_param(kw, "🟩", EnumConvertType.MASK, None)
B = parse_param(kw, "🟦", EnumConvertType.MASK, None)
A = parse_param(kw, "⬜", EnumConvertType.MASK, None)
mode = parse_param(kw, "MODE", EnumScaleMode, EnumScaleMode.MATTE.name)
wihi = parse_param(kw, "WH", EnumConvertType.VEC2INT, (512, 512), IMAGE_SIZE_MIN)
sample = parse_param(kw, "SAMPLE", EnumInterpolation, EnumInterpolation.LANCZOS4.name)
matte = parse_param(kw, "MATTE", EnumConvertType.VEC4INT, (0, 0, 0, 255), 0, 255)
flip = parse_param(kw, "FLIP", EnumConvertType.VEC4, (0, 0, 0, 0), 0., 1.)
invert = parse_param(kw, "INVERT", EnumConvertType.BOOLEAN, False)
rgba = parse_param(kw, Lexicon.IMAGE, EnumConvertType.IMAGE, None)
R = parse_param(kw, Lexicon.CHAN_RED, EnumConvertType.MASK, None)
G = parse_param(kw, Lexicon.CHAN_GREEN, EnumConvertType.MASK, None)
B = parse_param(kw, Lexicon.CHAN_BLUE, EnumConvertType.MASK, None)
A = parse_param(kw, Lexicon.CHAN_ALPHA, EnumConvertType.MASK, None)
mode = parse_param(kw, Lexicon.MODE, EnumScaleMode, EnumScaleMode.MATTE.name)
wihi = parse_param(kw, Lexicon.WH, EnumConvertType.VEC2INT, (512, 512), IMAGE_SIZE_MIN)
sample = parse_param(kw, Lexicon.SAMPLE, EnumInterpolation, EnumInterpolation.LANCZOS4.name)
matte = parse_param(kw, Lexicon.MATTE, EnumConvertType.VEC4INT, (0, 0, 0, 255), 0, 255)
flip = parse_param(kw, Lexicon.FLIP, EnumConvertType.VEC4, (0, 0, 0, 0), 0., 1.)
invert = parse_param(kw, Lexicon.INVERT, EnumConvertType.BOOLEAN, False)
params = list(zip_longest_fill(rgba, R, G, B, A, mode, wihi, sample, matte, flip, invert))
images = []
pbar = ProgressBar(len(params))
@@ -498,16 +467,14 @@ Takes an input image and splits it into its individual color channels (red, gree
d = super().INPUT_TYPES()
d = deep_merge(d, {
"optional": {
"IMAGE": (COZY_TYPE_IMAGE, {
"tooltip": "Pixel Data (RGBA, RGB or Grayscale)"
})
Lexicon.IMAGE: (COZY_TYPE_IMAGE, {})
}
})
return d
return Lexicon._parse(d)
def run(self, **kw) -> RGBAMaskType:
images = []
pA = parse_param(kw, "IMAGE", EnumConvertType.IMAGE, None)
pA = parse_param(kw, Lexicon.IMAGE, EnumConvertType.IMAGE, None)
pbar = ProgressBar(len(pA))
for idx, pA in enumerate(pA):
pA = channel_solid(chan=EnumImageType.BGRA) if pA is None else tensor_to_cv(pA)
@@ -528,39 +495,30 @@ Swap pixel values between two input images based on specified channel swizzle op
d = super().INPUT_TYPES()
d = deep_merge(d, {
"optional": {
"IMAGE_A": (COZY_TYPE_IMAGE, {
"tooltip": "Pixel Data (RGBA, RGB or Grayscale)"
}),
"IMAGE_B": (COZY_TYPE_IMAGE, {
"tooltip": "Pixel Data (RGBA, RGB or Grayscale)"
}),
"SWAP_R": (EnumPixelSwizzle._member_names_, {
"default": EnumPixelSwizzle.RED_A.name,
"tooltip": "Replace input Red channel with target channel or constant"}),
"SWAP_G": (EnumPixelSwizzle._member_names_, {
"default": EnumPixelSwizzle.GREEN_A.name,
"tooltip": "Replace input Green channel with target channel or constant"}),
"SWAP_B": (EnumPixelSwizzle._member_names_, {
"default": EnumPixelSwizzle.BLUE_A.name,
"tooltip": "Replace input Blue channel with target channel or constant"}),
"SWAP_A": (EnumPixelSwizzle._member_names_, {
"default": EnumPixelSwizzle.ALPHA_A.name,
"tooltip": "Replace input Alpha channel with target channel or constant"}),
"MATTE": ("VEC4", {
"default": (0, 0, 0, 255), "rgb": True,
"tooltip": "Background Color"})
Lexicon.IMAGE_SOURCE: (COZY_TYPE_IMAGE, {}),
Lexicon.IMAGE_TARGET: (COZY_TYPE_IMAGE, {}),
Lexicon.SWAP_R: (EnumPixelSwizzle._member_names_, {
"default": EnumPixelSwizzle.RED_A.name,}),
Lexicon.SWAP_G: (EnumPixelSwizzle._member_names_, {
"default": EnumPixelSwizzle.GREEN_A.name,}),
Lexicon.SWAP_B: (EnumPixelSwizzle._member_names_, {
"default": EnumPixelSwizzle.BLUE_A.name,}),
Lexicon.SWAP_A: (EnumPixelSwizzle._member_names_, {
"default": EnumPixelSwizzle.ALPHA_A.name,}),
Lexicon.MATTE: ("VEC4", {
"default": (0, 0, 0, 255), "rgb": True,})
}
})
return d
return Lexicon._parse(d)
def run(self, **kw) -> RGBAMaskType:
pA = parse_param(kw, "IMAGE_A", EnumConvertType.IMAGE, None)
pB = parse_param(kw, "IMAGE_B", EnumConvertType.IMAGE, None)
swap_r = parse_param(kw, "SWAP_R", EnumPixelSwizzle, EnumPixelSwizzle.RED_A.name)
swap_g = parse_param(kw, "SWAP_G", EnumPixelSwizzle, EnumPixelSwizzle.GREEN_A.name)
swap_b = parse_param(kw, "SWAP_B", EnumPixelSwizzle, EnumPixelSwizzle.BLUE_A.name)
swap_a = parse_param(kw, "SWAP_A", EnumPixelSwizzle, EnumPixelSwizzle.ALPHA_A.name)
matte = parse_param(kw, "MATTE", EnumConvertType.VEC4INT, (0, 0, 0, 255), 0, 255)
pA = parse_param(kw, Lexicon.IMAGE_SOURCE, EnumConvertType.IMAGE, None)
pB = parse_param(kw, Lexicon.IMAGE_TARGET, EnumConvertType.IMAGE, None)
swap_r = parse_param(kw, Lexicon.SWAP_R, EnumPixelSwizzle, EnumPixelSwizzle.RED_A.name)
swap_g = parse_param(kw, Lexicon.SWAP_G, EnumPixelSwizzle, EnumPixelSwizzle.GREEN_A.name)
swap_b = parse_param(kw, Lexicon.SWAP_B, EnumPixelSwizzle, EnumPixelSwizzle.BLUE_A.name)
swap_a = parse_param(kw, Lexicon.SWAP_A, EnumPixelSwizzle, EnumPixelSwizzle.ALPHA_A.name)
matte = parse_param(kw, Lexicon.MATTE, EnumConvertType.VEC4INT, (0, 0, 0, 255), 0, 255)
params = list(zip_longest_fill(pA, pB, swap_r, swap_g, swap_b, swap_a, matte))
images = []
pbar = ProgressBar(len(params))
@@ -602,32 +560,29 @@ Define a range and apply it to an image for segmentation and feature extraction.
d = super().INPUT_TYPES()
d = deep_merge(d, {
"optional": {
"IMAGE": (COZY_TYPE_IMAGE, {
"tooltip": "Pixel Data (RGBA, RGB or Grayscale)"
}),
"ADAPT": ( EnumThresholdAdapt._member_names_, {
"default": EnumThresholdAdapt.ADAPT_NONE.name,
"tooltip": "X-Men"}),
"FUNCTION": ( EnumThreshold._member_names_, {
Lexicon.IMAGE: (COZY_TYPE_IMAGE, {}),
Lexicon.ADAPT: ( EnumThresholdAdapt._member_names_, {
"default": EnumThresholdAdapt.ADAPT_NONE.name,}),
Lexicon.FUNCTION: ( EnumThreshold._member_names_, {
"default": EnumThreshold.BINARY.name}),
"THRESHOLD": ("FLOAT", {
Lexicon.THRESHOLD: ("FLOAT", {
"default": 0.5, "min": 0, "max": 1, "step": 0.005}),
"SIZE": ("INT", {
Lexicon.SIZE: ("INT", {
"default": 3, "min": 3, "max": 103}),
"INVERT": ("BOOLEAN", {
Lexicon.INVERT: ("BOOLEAN", {
"default": False,
"tooltip": "Invert the mask input"})
}
})
return d
return Lexicon._parse(d)
def run(self, **kw) -> RGBAMaskType:
pA = parse_param(kw, "IMAGE", EnumConvertType.IMAGE, None)
mode = parse_param(kw, "FUNCTION", EnumThreshold, EnumThreshold.BINARY.name)
adapt = parse_param(kw, "ADAPT", EnumThresholdAdapt, EnumThresholdAdapt.ADAPT_NONE.name)
threshold = parse_param(kw, "THRESHOLD", EnumConvertType.FLOAT, 1, 0, 1)
block = parse_param(kw, "SIZE", EnumConvertType.INT, 3, 3)
invert = parse_param(kw, "INVERT", EnumConvertType.BOOLEAN, False)
pA = parse_param(kw, Lexicon.IMAGE, EnumConvertType.IMAGE, None)
mode = parse_param(kw, Lexicon.FUNCTION, EnumThreshold, EnumThreshold.BINARY.name)
adapt = parse_param(kw, Lexicon.ADAPT, EnumThresholdAdapt, EnumThresholdAdapt.ADAPT_NONE.name)
threshold = parse_param(kw, Lexicon.THRESHOLD, EnumConvertType.FLOAT, 1, 0, 1)
block = parse_param(kw, Lexicon.SIZE, EnumConvertType.INT, 3, 3)
invert = parse_param(kw, Lexicon.INVERT, EnumConvertType.BOOLEAN, False)
params = list(zip_longest_fill(pA, mode, adapt, threshold, block, invert))
images = []
pbar = ProgressBar(len(params))
@@ -656,14 +611,14 @@ The Histogram Node generates a histogram representation of the input image, show
d = super().INPUT_TYPES()
d = deep_merge(d, {
"optional": {
"IMAGE": (COZY_TYPE_IMAGE, {
Lexicon.IMAGE": (COZY_TYPE_IMAGE, {
"tooltip": "Pixel Data (RGBA, RGB or Grayscale)"}),
}
})
return d
return Lexicon._parse(d)
def run(self, **kw) -> RGBAMaskType:
pA = parse_param(kw, "IMAGE", None), EnumConvertType.IMAGE, None)
pA = parse_param(kw, Lexicon.IMAGE", None), EnumConvertType.IMAGE, None)
params = list(zip_longest_fill(pA,))
images = []
pbar = ProgressBar(len(params))
+86 -195
View File
@@ -11,6 +11,9 @@ from cozy_comfyui import \
InputType, EnumConvertType, RGBAMaskType, \
deep_merge, parse_param, zip_longest_fill
from cozy_comfyui.lexicon import \
Lexicon
from cozy_comfyui.node import \
COZY_TYPE_IMAGE, \
CozyImageNode
@@ -58,34 +61,31 @@ Generate a constant image or mask of a specified size and color. It can be used
d = super().INPUT_TYPES()
d = deep_merge(d, {
"optional": {
"IMAGE": (COZY_TYPE_IMAGE, {
Lexicon.IMAGE: (COZY_TYPE_IMAGE, {
"tooltip":"Optional Image to Matte with Selected Color"}),
"MASK": (COZY_TYPE_IMAGE, {
Lexicon.MASK: (COZY_TYPE_IMAGE, {
"tooltip":"Override Image mask"}),
"COLOR": ("VEC4", {
Lexicon.COLOR: ("VEC4", {
"default": (0, 0, 0, 255), "rgb": True,
"tooltip": "Constant Color to Output"}),
"MODE": (EnumScaleMode._member_names_, {
"default": EnumScaleMode.MATTE.name,
"tooltip": "If the image should be resized to fit within given dimensions or keep the original size"}),
"WH": ("VEC2", {
Lexicon.MODE: (EnumScaleMode._member_names_, {
"default": EnumScaleMode.MATTE.name,}),
Lexicon.WH: ("VEC2", {
"default": (512, 512), "int": True,
"label": ["W", "H"],
"tooltip": "Desired Width and Height of the Color Output"}),
"SAMPLE": (EnumInterpolation._member_names_, {
"default": EnumInterpolation.LANCZOS4.name,
"tooltip": "Sampling method for resizing images"})
"label": ["W", "H"],}),
Lexicon.SAMPLE: (EnumInterpolation._member_names_, {
"default": EnumInterpolation.LANCZOS4.name,})
}
})
return d
return Lexicon._parse(d)
def run(self, **kw) -> RGBAMaskType:
pA = parse_param(kw, "IMAGE", EnumConvertType.IMAGE, None)
mask = parse_param(kw, "MASK", EnumConvertType.IMAGE, None)
matte = parse_param(kw, "COLOR", EnumConvertType.VEC4INT, (0, 0, 0, 255), 0, 255)
wihi = parse_param(kw, "WH", EnumConvertType.VEC2INT, (512, 512), IMAGE_SIZE_MIN)
mode = parse_param(kw, "MODE", EnumScaleMode, EnumScaleMode.MATTE.name)
sample = parse_param(kw, "SAMPLE", EnumInterpolation, EnumInterpolation.LANCZOS4.name)
pA = parse_param(kw, Lexicon.IMAGE, EnumConvertType.IMAGE, None)
mask = parse_param(kw, Lexicon.MASK, EnumConvertType.IMAGE, None)
matte = parse_param(kw, Lexicon.COLOR, EnumConvertType.VEC4INT, (0, 0, 0, 255), 0, 255)
wihi = parse_param(kw, Lexicon.WH, EnumConvertType.VEC2INT, (512, 512), IMAGE_SIZE_MIN)
mode = parse_param(kw, Lexicon.MODE, EnumScaleMode, EnumScaleMode.MATTE.name)
sample = parse_param(kw, Lexicon.SAMPLE, EnumInterpolation, EnumInterpolation.LANCZOS4.name)
images = []
params = list(zip_longest_fill(pA, mask, matte, wihi, mode, sample))
pbar = ProgressBar(len(params))
@@ -125,47 +125,43 @@ Create n-sided polygons. These shapes can be customized by adjusting parameters
d = super().INPUT_TYPES()
d = deep_merge(d, {
"optional": {
"SHAPE": (EnumShapes._member_names_, {
Lexicon.SHAPE: (EnumShapes._member_names_, {
"default": EnumShapes.CIRCLE.name}),
"SIDES": ("INT", {
Lexicon.SIDES: ("INT", {
"default": 3, "min": 3, "max": 100}),
"COLOR": ("VEC4", {
Lexicon.COLOR: ("VEC4", {
"default": (255, 255, 255, 255), "rgb": True,
"tooltip": "Main Shape Color"}),
"MATTE": ("VEC4", {
"default": (0, 0, 0, 255), "rgb": True,
"tooltip": "Background Color"}),
"WH": ("VEC2", {
Lexicon.MATTE: ("VEC4", {
"default": (0, 0, 0, 255), "rgb": True,}),
Lexicon.WH: ("VEC2", {
"default": (256, 256), "mij":IMAGE_SIZE_MIN, "int": True,
"label": ["W", "H"],
"tooltip": "Width and Height"}),
"XY": ("VEC2", {
"label": ["W", "H"],}),
Lexicon.XY: ("VEC2", {
"default": (0, 0,), "label": ["X", "Y"]}),
"ANGLE": ("FLOAT", {
"default": 0, "min": -180, "max": 180, "step": 0.01,
"tooltip": "Rotation Angle"}),
"SIZE": ("VEC2", {
Lexicon.ANGLE: ("FLOAT", {
"default": 0, "min": -180, "max": 180, "step": 0.01,}),
Lexicon.SIZE: ("VEC2", {
"default": (1., 1.), "label": ["X", "Y"]}),
"EDGE": (EnumEdge._member_names_, {
Lexicon.EDGE: (EnumEdge._member_names_, {
"default": EnumEdge.CLIP.name}),
"BLUR": ("FLOAT", {
"default": 0, "min": 0, "step": 0.01,
"tooltip": "Edge blur amount (Gaussian blur)"}),
Lexicon.BLUR: ("FLOAT", {
"default": 0, "min": 0, "step": 0.01,}),
}
})
return d
return Lexicon._parse(d)
def run(self, **kw) -> RGBAMaskType:
shape = parse_param(kw, "SHAPE", EnumShapes, EnumShapes.CIRCLE.name)
sides = parse_param(kw, "SIDES", EnumConvertType.INT, 3, 3, 100)
angle = parse_param(kw, "ANGLE", EnumConvertType.FLOAT, 0)
edge = parse_param(kw, "EDGE", EnumEdge, EnumEdge.CLIP.name)
offset = parse_param(kw, "XY", EnumConvertType.VEC2, (0, 0))
size = parse_param(kw, "SIZE", EnumConvertType.VEC2, (1, 1), zero=0.001)
wihi = parse_param(kw, "WH", EnumConvertType.VEC2INT, (256, 256), IMAGE_SIZE_MIN)
color = parse_param(kw, "COLOR", EnumConvertType.VEC4INT, (255, 255, 255, 255), 0, 255)
matte = parse_param(kw, "MATTE", EnumConvertType.VEC4INT, (0, 0, 0, 255), 0, 255)
blur = parse_param(kw, "BLUR", EnumConvertType.FLOAT, 0)
shape = parse_param(kw, Lexicon.SHAPE, EnumShapes, EnumShapes.CIRCLE.name)
sides = parse_param(kw, Lexicon.SIDES, EnumConvertType.INT, 3, 3, 100)
angle = parse_param(kw, Lexicon.ANGLE, EnumConvertType.FLOAT, 0)
edge = parse_param(kw, Lexicon.EDGE, EnumEdge, EnumEdge.CLIP.name)
offset = parse_param(kw, Lexicon.XY, EnumConvertType.VEC2, (0, 0))
size = parse_param(kw, Lexicon.SIZE, EnumConvertType.VEC2, (1, 1), zero=0.001)
wihi = parse_param(kw, Lexicon.WH, EnumConvertType.VEC2INT, (256, 256), IMAGE_SIZE_MIN)
color = parse_param(kw, Lexicon.COLOR, EnumConvertType.VEC4INT, (255, 255, 255, 255), 0, 255)
matte = parse_param(kw, Lexicon.MATTE, EnumConvertType.VEC4INT, (0, 0, 0, 255), 0, 255)
blur = parse_param(kw, Lexicon.BLUR, EnumConvertType.FLOAT, 0)
params = list(zip_longest_fill(shape, sides, offset, angle, edge, size, wihi, color, matte, blur))
images = []
pbar = ProgressBar(len(params))
@@ -217,78 +213,71 @@ Generates images containing text based on parameters such as font, size, alignme
d = super().INPUT_TYPES()
d = deep_merge(d, {
"optional": {
"STRING": ("STRING", {
Lexicon.STRING: ("STRING", {
"default": "jovimetrix", "multiline": True,
"dynamicPrompts": False,
"tooltip": "Your Message"}),
"FONT": (cls.FONT_NAMES, {
Lexicon.FONT: (cls.FONT_NAMES, {
"default": cls.FONT_NAMES[0]}),
"LETTER": ("BOOLEAN", {
"default": False,
"tooltip": "If each letter be generated and output in a batch"}),
"AUTOSIZE": ("BOOLEAN", {
Lexicon.LETTER: ("BOOLEAN", {
"default": False,}),
Lexicon.AUTOSIZE: ("BOOLEAN", {
"default": False,
"tooltip": "Scale based on Width & Height"}),
"COLOR": ("VEC4", {
Lexicon.COLOR: ("VEC4", {
"default": (255, 255, 255, 255), "rgb": True,
"tooltip": "Color of the letters"}),
"MATTE": ("VEC4", {
"default": (0, 0, 0, 255), "rgb": True,
"tooltip": "Background Color"}),
"COLS": ("INT", {
Lexicon.MATTE: ("VEC4", {
"default": (0, 0, 0, 255), "rgb": True,}),
Lexicon.COLUMNS: ("INT", {
"default": 0, "min": 0}),
# if auto on, hide these...
"SIZE": ("INT", {
Lexicon.SIZE: ("INT", {
"default": 16, "min": 8}),
"ALIGN": (EnumAlignment._member_names_, {
"default": EnumAlignment.CENTER.name,
"tooltip": "Top, Center or Bottom alignment"}),
"JUSTIFY": (EnumJustify._member_names_, {
"default": EnumJustify.CENTER.name,
"tooltip": "How to align the text to the side margins of the canvas: Left, Right, or Centered"}),
"MARGIN": ("INT", {
"default": 0, "min": -1024, "max": 1024,
"tooltip": "Whitespace padding around canvas"}),
"SPACING": ("INT", {
Lexicon.ALIGN: (EnumAlignment._member_names_, {
"default": EnumAlignment.CENTER.name,}),
Lexicon.JUSTIFY: (EnumJustify._member_names_, {
"default": EnumJustify.CENTER.name,}),
Lexicon.MARGIN: ("INT", {
"default": 0, "min": -1024, "max": 1024,}),
Lexicon.SPACING: ("INT", {
"default": 0, "min": -1024, "max": 1024}),
"WH": ("VEC2", {
Lexicon.WH: ("VEC2", {
"default": (256, 256), "mij":IMAGE_SIZE_MIN, "int": True,
"label": ["W", "H"],
"tooltip": "Width and Height"}),
"XY": ("VEC2", {
"label": ["W", "H"],}),
Lexicon.XY: ("VEC2", {
"default": (0, 0,), "mij": -1, "maj": 1,
"label": ["X", "Y"],
"tooltip":"Offset the position"}),
"ANGLE": ("FLOAT", {
"default": 0, "step": 0.01,
"tooltip": "Rotation Angle"}),
"EDGE": (EnumEdge._member_names_, {
Lexicon.ANGLE: ("FLOAT", {
"default": 0, "step": 0.01,}),
Lexicon.EDGE: (EnumEdge._member_names_, {
"default": EnumEdge.CLIP.name}),
"INVERT": ("BOOLEAN", {
Lexicon.INVERT: ("BOOLEAN", {
"default": False,
"tooltip": "Invert the mask input"})
}
})
return d
return Lexicon._parse(d)
def run(self, **kw) -> RGBAMaskType:
full_text = parse_param(kw, "STRING", EnumConvertType.STRING, "jovimetrix")
font_idx = parse_param(kw, "FONT", EnumConvertType.STRING, self.FONT_NAMES[0])
autosize = parse_param(kw, "AUTOSIZE", EnumConvertType.BOOLEAN, False)
letter = parse_param(kw, "LETTER", EnumConvertType.BOOLEAN, False)
color = parse_param(kw, "COLOR", EnumConvertType.VEC4INT, (255,255,255,255), 0, 255)
matte = parse_param(kw, "MATTE", EnumConvertType.VEC4INT, (0,0,0,255), 0, 255)
columns = parse_param(kw, "COLS", EnumConvertType.INT, 0)
font_size = parse_param(kw, "SIZE", EnumConvertType.INT, 1)
align = parse_param(kw, "ALIGN", EnumAlignment, EnumAlignment.CENTER.name)
justify = parse_param(kw, "JUSTIFY", EnumJustify, EnumJustify.CENTER.name)
margin = parse_param(kw, "MARGIN", EnumConvertType.INT, 0)
line_spacing = parse_param(kw, "SPACING", EnumConvertType.INT, 0)
wihi = parse_param(kw, "WH", EnumConvertType.VEC2INT, (512, 512), IMAGE_SIZE_MIN)
pos = parse_param(kw, "XY", EnumConvertType.VEC2, (0, 0), -1, 1)
angle = parse_param(kw, "ANGLE", EnumConvertType.INT, 0)
edge = parse_param(kw, "EDGE", EnumEdge, EnumEdge.CLIP.name)
invert = parse_param(kw, "INVERT", EnumConvertType.BOOLEAN, False)
full_text = parse_param(kw, Lexicon.STRING, EnumConvertType.STRING, "jovimetrix")
font_idx = parse_param(kw, Lexicon.FONT, EnumConvertType.STRING, self.FONT_NAMES[0])
autosize = parse_param(kw, Lexicon.AUTOSIZE, EnumConvertType.BOOLEAN, False)
letter = parse_param(kw, Lexicon.LETTER, EnumConvertType.BOOLEAN, False)
color = parse_param(kw, Lexicon.COLOR, EnumConvertType.VEC4INT, (255,255,255,255), 0, 255)
matte = parse_param(kw, Lexicon.MATTE, EnumConvertType.VEC4INT, (0,0,0,255), 0, 255)
columns = parse_param(kw, Lexicon.COLUMNS, EnumConvertType.INT, 0)
font_size = parse_param(kw, Lexicon.SIZE, EnumConvertType.INT, 1)
align = parse_param(kw, Lexicon.ALIGN, EnumAlignment, EnumAlignment.CENTER.name)
justify = parse_param(kw, Lexicon.JUSTIFY, EnumJustify, EnumJustify.CENTER.name)
margin = parse_param(kw, Lexicon.MARGIN, EnumConvertType.INT, 0)
line_spacing = parse_param(kw, Lexicon.SPACING, EnumConvertType.INT, 0)
wihi = parse_param(kw, Lexicon.WH, EnumConvertType.VEC2INT, (512, 512), IMAGE_SIZE_MIN)
pos = parse_param(kw, Lexicon.XY, EnumConvertType.VEC2, (0, 0), -1, 1)
angle = parse_param(kw, Lexicon.ANGLE, EnumConvertType.INT, 0)
edge = parse_param(kw, Lexicon.EDGE, EnumEdge, EnumEdge.CLIP.name)
invert = parse_param(kw, Lexicon.INVERT, EnumConvertType.BOOLEAN, False)
images = []
params = list(zip_longest_fill(full_text, font_idx, autosize, letter, color,
matte, columns, font_size, align, justify, margin,
@@ -328,101 +317,3 @@ Generates images containing text based on parameters such as font, size, alignme
images.append(cv_to_tensor_full(img, matte))
pbar.update_absolute(idx)
return image_stack(images)
'''
class StereogramNode(CozyImageNode):
NAME = "STEREOGRAM (JOV) 📻"
CATEGORY = JOV_CATEGORY
DESCRIPTION = """
Generates false perception 3D images from 2D input. Set tile divisions, noise, gamma, and shift parameters to control the stereogram's appearance.
"""
@classmethod
def INPUT_TYPES(cls) -> InputType:
d = super().INPUT_TYPES()
d = deep_merge(d, {
"optional": {
"IMAGE": (COZY_TYPE_IMAGE, {
"tooltip": "Pixel Data (RGBA, RGB or Grayscale)"
}),
"DEPTH": (COZY_TYPE_IMAGE, {
"tooltip": "Grayscale image representing a depth map"
}),
"TILE": ("INT", {
"default": 8, "min": 1}),
"NOISE": ("FLOAT", {
"default": 0.33, "min": 0, "max": 1, "step": 0.01}),
"GAMMA": ("FLOAT", {
"default": 0.33, "min": 0, "max": 1, "step": 0.01}),
"SHIFT": ("FLOAT", {
"default": 1., "min": -1, "max": 1, "step": 0.01}),
"INVERT": ("BOOLEAN", {
"default": False}),
}
})
return d
def run(self, **kw) -> RGBAMaskType:
pA = parse_param(kw, "IMAGE", EnumConvertType.IMAGE, None)
depth = parse_param(kw, "DEPTH", EnumConvertType.IMAGE, None)
divisions = parse_param(kw, "TILE", EnumConvertType.INT, 1, 1, 8)
noise = parse_param(kw, "NOISE", EnumConvertType.FLOAT, 1, 0)
gamma = parse_param(kw, "GAMMA", EnumConvertType.FLOAT, 1, 0)
shift = parse_param(kw, "SHIFT", EnumConvertType.FLOAT, 0, 1, -1)
invert = parse_param(kw, "INVERT", EnumConvertType.BOOLEAN, False)
params = list(zip_longest_fill(pA, depth, divisions, noise, gamma, shift, invert))
images = []
pbar = ProgressBar(len(params))
for idx, (pA, depth, divisions, noise, gamma, shift, invert) in enumerate(params):
pA = channel_solid(chan=EnumImageType.BGRA) if pA is None else tensor_to_cv(pA)
h, w = pA.shape[:2]
depth = channel_solid(w, h, chan=EnumImageType.BGRA) if depth is None else tensor_to_cv(depth)
if invert:
depth = image_invert(depth, 1.0)
pA = image_stereogram(pA, depth, divisions, noise, gamma, shift)
images.append(cv_to_tensor_full(pA))
pbar.update_absolute(idx)
return image_stack(images)
class StereoscopicNode(CozyBaseNode):
NAME = "STEREOSCOPIC (JOV) 🕶️"
CATEGORY = JOV_CATEGORY
RETURN_TYPES = ("IMAGE", )
RETURN_NAMES = ("IMAGE", )
DESCRIPTION = """
Simulates depth perception in images by generating stereoscopic views. It accepts an optional input image for color matte. Adjust baseline and focal length for customized depth effects.
"""
@classmethod
def INPUT_TYPES(cls) -> InputType:
d = super().INPUT_TYPES()
d = deep_merge(d, {
"optional": {
"IMAGE": (COZY_TYPE_IMAGE, {
"tooltip":"Optional Image to Matte with Selected Color"}),
"INT": ("FLOAT", {
"default": 0.1, "min": 0, "max": 1, "step": 0.01,
"tooltip":"Baseline"}),
"FOCAL": ("FLOAT", {
"default": 500, "min": 0, "step": 0.01}),
}
})
return d
def run(self, **kw) -> tuple[TensorType]:
pA = parse_param(kw, "IMAGE", EnumConvertType.IMAGE, None)
baseline = parse_param(kw, "INT", EnumConvertType.FLOAT, 0, 0.1, 1)
focal_length = parse_param(kw, "VAL", EnumConvertType.FLOAT, 500, 0)
images = []
params = list(zip_longest_fill(pA, baseline, focal_length))
pbar = ProgressBar(len(params))
for idx, (pA, baseline, focal_length) in enumerate(params):
pA = tensor_to_cv(pA) if pA is not None else channel_solid(chan=EnumImageType.GRAYSCALE)
# Convert depth image to disparity map
disparity_map = np.divide(1.0, pA.astype(np.float32), where=pA!=0)
# Compute disparity values based on baseline and focal length
disparity_map *= baseline * focal_length
images.append(cv_to_tensor(pA))
pbar.update_absolute(idx)
return torch.stack(images)
'''
+94 -111
View File
@@ -10,6 +10,9 @@ from cozy_comfyui import \
InputType, RGBAMaskType, EnumConvertType, \
deep_merge, parse_param, parse_dynamic, zip_longest_fill
from cozy_comfyui.lexicon import \
Lexicon
from cozy_comfyui.node import \
COZY_TYPE_IMAGE, \
CozyImageNode
@@ -72,41 +75,36 @@ Extract a portion of an input image or resize it. It supports various cropping m
d = super().INPUT_TYPES()
d = deep_merge(d, {
"optional": {
"IMAGE": (COZY_TYPE_IMAGE, {
"tooltip": "Pixel Data (RGBA, RGB or Grayscale)"
}),
"FUNCTION": (EnumCropMode._member_names_, {
Lexicon.IMAGE: (COZY_TYPE_IMAGE, {}),
Lexicon.FUNCTION: (EnumCropMode._member_names_, {
"default": EnumCropMode.CENTER.name}),
"XY": ("VEC2", {
Lexicon.XY: ("VEC2", {
"default": (0, 0), "mij": 0.5, "maj": 0.5,
"label": ["X", "Y"]}),
"WH": ("VEC2", {
Lexicon.WH: ("VEC2", {
"default": (512, 512), "mij": IMAGE_SIZE_MIN, "int": True,
"label": ["W", "H"]}),
"TLTR": ("VEC4", {
Lexicon.TLTR: ("VEC4", {
"default": (0, 0, 0, 1), "mij": 0, "maj": 1,
"label": ["TOP", "LEFT", "TOP", "RIGHT"],
"tooltip": "Top Left - Top Right"}),
"BLBR": ("VEC4", {
"label": ["TOP", "LEFT", "TOP", "RIGHT"],}),
Lexicon.BLBR: ("VEC4", {
"default": (1, 0, 1, 1), "mij": 0, "maj": 1,
"label": ["BOTTOM", "LEFT", "BOTTOM", "RIGHT"],
"tooltip": "Bottom Left - Bottom Right"}),
"MATTE": ("VEC4", {
"default": (0, 0, 0, 255), "rgb": True,
"tooltip": "Background Color"})
"label": ["BOTTOM", "LEFT", "BOTTOM", "RIGHT"],}),
Lexicon.MATTE: ("VEC4", {
"default": (0, 0, 0, 255), "rgb": True,})
}
})
return d
return Lexicon._parse(d)
def run(self, **kw) -> RGBAMaskType:
pA = parse_param(kw, "IMAGE", EnumConvertType.IMAGE, None)
func = parse_param(kw, "FUNCTION", EnumCropMode, EnumCropMode.CENTER.name)
pA = parse_param(kw, Lexicon.IMAGE, EnumConvertType.IMAGE, None)
func = parse_param(kw, Lexicon.FUNCTION, EnumCropMode, EnumCropMode.CENTER.name)
# if less than 1 then use as scalar, over 1 = int(size)
xy = parse_param(kw, "XY", EnumConvertType.VEC2, (0, 0,), 0, 1)
wihi = parse_param(kw, "WH", EnumConvertType.VEC2INT, (512, 512), IMAGE_SIZE_MIN)
tltr = parse_param(kw, "TLTR", EnumConvertType.VEC4, (0, 0, 0, 1,), 0, 1)
blbr = parse_param(kw, "BLBR", EnumConvertType.VEC4, (1, 0, 1, 1,), 0, 1)
matte = parse_param(kw, "MATTE", EnumConvertType.VEC4INT, (0, 0, 0, 255), 0, 255)
xy = parse_param(kw, Lexicon.XY, EnumConvertType.VEC2, (0, 0,), 0, 1)
wihi = parse_param(kw, Lexicon.WH, EnumConvertType.VEC2INT, (512, 512), IMAGE_SIZE_MIN)
tltr = parse_param(kw, Lexicon.TLTR, EnumConvertType.VEC4, (0, 0, 0, 1,), 0, 1)
blbr = parse_param(kw, Lexicon.BLBR, EnumConvertType.VEC4, (1, 0, 1, 1,), 0, 1)
matte = parse_param(kw, Lexicon.MATTE, EnumConvertType.VEC4INT, (0, 0, 0, 255), 0, 255)
params = list(zip_longest_fill(pA, func, xy, wihi, tltr, blbr, matte))
images = []
pbar = ProgressBar(len(params))
@@ -151,34 +149,31 @@ Combine multiple input images into a single image by summing their pixel values.
d = super().INPUT_TYPES()
d = deep_merge(d, {
"optional": {
"MODE": (EnumScaleMode._member_names_, {
"default": EnumScaleMode.MATTE.name,
"tooltip": "If the image should be resized to fit within given dimensions or keep the original size"}),
"WH": ("VEC2", {
Lexicon.MODE: (EnumScaleMode._member_names_, {
"default": EnumScaleMode.MATTE.name,}),
Lexicon.WH: ("VEC2", {
"default": (512, 512), "mij":IMAGE_SIZE_MIN, "int": True,
"label": ["W", "H"]}),
"SAMPLE": (EnumInterpolation._member_names_, {
"default": EnumInterpolation.LANCZOS4.name,
"tooltip": "Sampling method for resizing images"}),
"MATTE": ("VEC4", {
"default": (0, 0, 0, 255), "rgb": True,
"tooltip": "Background Color"})
Lexicon.SAMPLE: (EnumInterpolation._member_names_, {
"default": EnumInterpolation.LANCZOS4.name,}),
Lexicon.MATTE: ("VEC4", {
"default": (0, 0, 0, 255), "rgb": True,})
}
})
return d
return Lexicon._parse(d)
def run(self, **kw) -> RGBAMaskType:
imgs = parse_dynamic(kw, "IMAGE", EnumConvertType.IMAGE, None)
imgs = parse_dynamic(kw, Lexicon.IMAGE, EnumConvertType.IMAGE, None)
if imgs is None:
logger.warning("no images to flatten")
return ()
# be less dumb when merging
pA = [tensor_to_cv(i) for i in imgs]
mode = parse_param(kw, "MODE", EnumScaleMode, EnumScaleMode.MATTE.name)
wihi = parse_param(kw, "WH", EnumConvertType.VEC2INT, (512, 512), IMAGE_SIZE_MIN)
sample = parse_param(kw, "SAMPLE", EnumInterpolation, EnumInterpolation.LANCZOS4.name)
matte = parse_param(kw, "MATTE", EnumConvertType.VEC4INT, (0, 0, 0, 255), 0, 255)
mode = parse_param(kw, Lexicon.MODE, EnumScaleMode, EnumScaleMode.MATTE.name)
wihi = parse_param(kw, Lexicon.WH, EnumConvertType.VEC2INT, (512, 512), IMAGE_SIZE_MIN)
sample = parse_param(kw, Lexicon.SAMPLE, EnumInterpolation, EnumInterpolation.LANCZOS4.name)
matte = parse_param(kw, Lexicon.MATTE, EnumConvertType.VEC4INT, (0, 0, 0, 255), 0, 255)
images = []
params = list(zip_longest_fill(mode, sample, wihi, matte))
@@ -206,41 +201,37 @@ The axis parameter allows for horizontal, vertical, or grid stacking of images,
d = super().INPUT_TYPES()
d = deep_merge(d, {
"optional": {
"AXIS": (EnumOrientation._member_names_, {
"default": EnumOrientation.GRID.name,
"tooltip":"Choose the direction in which to stack the images. Options include horizontal, vertical, or a grid layout"}),
"STEP": ("INT", {
Lexicon.AXIS: (EnumOrientation._member_names_, {
"default": EnumOrientation.GRID.name,}),
Lexicon.STEP: ("INT", {
"default": 1, "min": 0,
"tooltip":"How many images are placed before a new row starts (stride)."}),
"MODE": (EnumScaleMode._member_names_, {
"default": EnumScaleMode.MATTE.name,
"tooltip": "If the image should be resized to fit within given dimensions or keep the original size"}),
"WH": ("VEC2", {
"tooltip":"How many images are placed before a new row starts (stride)"}),
Lexicon.MODE: (EnumScaleMode._member_names_, {
"default": EnumScaleMode.MATTE.name,}),
Lexicon.WH: ("VEC2", {
"default": (512, 512), "mij":IMAGE_SIZE_MIN, "int": True,
"label": ["W", "H"]}),
"SAMPLE": (EnumInterpolation._member_names_, {
"default": EnumInterpolation.LANCZOS4.name,
"tooltip": "Sampling method for resizing images"}),
"MATTE": ("VEC4", {
"default": (0, 0, 0, 255), "rgb": True,
"tooltip": "Background Color"})
Lexicon.SAMPLE: (EnumInterpolation._member_names_, {
"default": EnumInterpolation.LANCZOS4.name,}),
Lexicon.MATTE: ("VEC4", {
"default": (0, 0, 0, 255), "rgb": True,})
}
})
return d
return Lexicon._parse(d)
def run(self, **kw) -> RGBAMaskType:
images = parse_dynamic(kw, "IMAGE", EnumConvertType.IMAGE, None)
images = parse_dynamic(kw, Lexicon.IMAGE, EnumConvertType.IMAGE, None)
if len(images) == 0:
logger.warning("no images to stack")
return
images = [tensor_to_cv(i) for i in images]
axis = parse_param(kw, "AXIS", EnumOrientation, EnumOrientation.GRID.name)[0]
stride = parse_param(kw, "STEP", EnumConvertType.INT, 1)[0]
mode = parse_param(kw, "MODE", EnumScaleMode, EnumScaleMode.MATTE.name)[0]
wihi = parse_param(kw, "WH", EnumConvertType.VEC2INT, (512, 512), IMAGE_SIZE_MIN)[0]
sample = parse_param(kw, "SAMPLE", EnumInterpolation, EnumInterpolation.LANCZOS4.name)[0]
matte = parse_param(kw, "MATTE", EnumConvertType.VEC4INT, (0, 0, 0, 255), 0, 255)[0]
axis = parse_param(kw, Lexicon.AXIS, EnumOrientation, EnumOrientation.GRID.name)[0]
stride = parse_param(kw, Lexicon.STEP, EnumConvertType.INT, 1)[0]
mode = parse_param(kw, Lexicon.MODE, EnumScaleMode, EnumScaleMode.MATTE.name)[0]
wihi = parse_param(kw, Lexicon.WH, EnumConvertType.VEC2INT, (512, 512), IMAGE_SIZE_MIN)[0]
sample = parse_param(kw, Lexicon.SAMPLE, EnumInterpolation, EnumInterpolation.LANCZOS4.name)[0]
matte = parse_param(kw, Lexicon.MATTE, EnumConvertType.VEC4INT, (0, 0, 0, 255), 0, 255)[0]
img = image_stacker(images, axis, stride) #, matte)
if mode != EnumScaleMode.MATTE:
w, h = wihi
@@ -261,76 +252,68 @@ Apply various geometric transformations to images, including translation, rotati
d = super().INPUT_TYPES(prompt=True, dynprompt=True)
d = deep_merge(d, {
"optional": {
"IMAGE": (COZY_TYPE_IMAGE, {
"tooltip": "Pixel Data (RGBA, RGB or Grayscale)"
}),
"MASK": (COZY_TYPE_IMAGE, {
Lexicon.IMAGE: (COZY_TYPE_IMAGE, {}),
Lexicon.MASK: (COZY_TYPE_IMAGE, {
"tooltip": "Override Image mask"}),
"XY": ("VEC2", {
Lexicon.XY: ("VEC2", {
"default": (0., 0.,), "mij": -1., "maj": 1.,
"label": ["X", "Y"]}),
"ANGLE": ("FLOAT", {
"default": 0, "step": 0.01,
"tooltip": "Rotation Angle"}),
"SIZE": ("VEC2", {
Lexicon.ANGLE: ("FLOAT", {
"default": 0, "step": 0.01,}),
Lexicon.SIZE: ("VEC2", {
"default": (1., 1.), "mij": 0.001,
"label": ["X", "Y"]}),
"TILE": ("VEC2", {
Lexicon.TILE: ("VEC2", {
"default": (1., 1.), "mij": 1.,
"label": ["X", "Y"]}),
"EDGE": (EnumEdge._member_names_, {
Lexicon.EDGE: (EnumEdge._member_names_, {
"default": EnumEdge.CLIP.name}),
"MIRROR": (EnumMirrorMode._member_names_, {
Lexicon.MIRROR: (EnumMirrorMode._member_names_, {
"default": EnumMirrorMode.NONE.name}),
"PIVOT": ("VEC2", {
Lexicon.PIVOT: ("VEC2", {
"default": (0.5, 0.5), "step": 0.005,
"label": ["X", "Y"]}),
"PROJ": (EnumProjection._member_names_, {
Lexicon.PROJECTION: (EnumProjection._member_names_, {
"default": EnumProjection.NORMAL.name}),
"TLTR": ("VEC4", {
Lexicon.TLTR: ("VEC4", {
"default": (0., 0., 1., 0.), "mij": 0., "maj": 1., "step": 0.005,
"label": ["TOP", "LEFT", "TOP", "RIGHT"],
"tooltip": "Top Left - Top Right"}),
"BLBR": ("VEC4", {
"label": ["TOP", "LEFT", "TOP", "RIGHT"],}),
Lexicon.BLBR: ("VEC4", {
"default": (0., 1., 1., 1.), "mij": 0., "maj": 1., "step": 0.005,
"label": ["BOTTOM", "LEFT", "BOTTOM", "RIGHT"],
"tooltip": "Bottom Left - Bottom Right"}),
"STRENGTH": ("FLOAT", {
"label": ["BOTTOM", "LEFT", "BOTTOM", "RIGHT"],}),
Lexicon.STRENGTH: ("FLOAT", {
"default": 1, "min": 0, "step": 0.005}),
"MODE": (EnumScaleMode._member_names_, {
"default": EnumScaleMode.MATTE.name,
"tooltip": "If the image should be resized to fit within given dimensions or keep the original size"}),
"WH": ("VEC2", {
Lexicon.MODE: (EnumScaleMode._member_names_, {
"default": EnumScaleMode.MATTE.name,}),
Lexicon.WH: ("VEC2", {
"default": (512, 512), "mij":IMAGE_SIZE_MIN, "int": True,
"label": ["W", "H"]}),
"SAMPLE": (EnumInterpolation._member_names_, {
"default": EnumInterpolation.LANCZOS4.name,
"tooltip": "Sampling method for resizing images"}),
"MATTE": ("VEC4", {
"default": (0, 0, 0, 255), "rgb": True,
"tooltip": "Background Color"})
Lexicon.SAMPLE: (EnumInterpolation._member_names_, {
"default": EnumInterpolation.LANCZOS4.name,}),
Lexicon.MATTE: ("VEC4", {
"default": (0, 0, 0, 255), "rgb": True,})
}
})
return d
return Lexicon._parse(d)
def run(self, **kw) -> RGBAMaskType:
pA = parse_param(kw, "IMAGE", EnumConvertType.IMAGE, None)
mask = parse_param(kw, "MASK", EnumConvertType.IMAGE, None)
offset = parse_param(kw, "XY", EnumConvertType.VEC2, (0., 0.), -2.5, 2.5)
angle = parse_param(kw, "ANGLE", EnumConvertType.FLOAT, 0)
size = parse_param(kw, "SIZE", EnumConvertType.VEC2, (1., 1.), 0.001)
edge = parse_param(kw, "EDGE", EnumEdge, EnumEdge.CLIP.name)
mirror = parse_param(kw, "MIRROR", EnumMirrorMode, EnumMirrorMode.NONE.name)
mirror_pivot = parse_param(kw, "PIVOT", EnumConvertType.VEC2, (0.5, 0.5), 0, 1)
tile_xy = parse_param(kw, "TILE", EnumConvertType.VEC2, (1., 1.), 1)
proj = parse_param(kw, "PROJ", EnumProjection, EnumProjection.NORMAL.name)
tltr = parse_param(kw, "TLTR", EnumConvertType.VEC4, (0., 0., 1., 0.), 0, 1)
blbr = parse_param(kw, "BLBR", EnumConvertType.VEC4, (0., 1., 1., 1.), 0, 1)
strength = parse_param(kw, "STRENGTH", EnumConvertType.FLOAT, 1, 0, 1)
mode = parse_param(kw, "MODE", EnumScaleMode, EnumScaleMode.MATTE.name)
wihi = parse_param(kw, "WH", EnumConvertType.VEC2INT, (512, 512), IMAGE_SIZE_MIN)
sample = parse_param(kw, "SAMPLE", EnumInterpolation, EnumInterpolation.LANCZOS4.name)
matte = parse_param(kw, "MATTE", EnumConvertType.VEC4INT, (0, 0, 0, 255), 0, 255)
pA = parse_param(kw, Lexicon.IMAGE, EnumConvertType.IMAGE, None)
mask = parse_param(kw, Lexicon.MASK, EnumConvertType.IMAGE, None)
offset = parse_param(kw, Lexicon.XY, EnumConvertType.VEC2, (0., 0.), -2.5, 2.5)
angle = parse_param(kw, Lexicon.ANGLE, EnumConvertType.FLOAT, 0)
size = parse_param(kw, Lexicon.SIZE, EnumConvertType.VEC2, (1., 1.), 0.001)
edge = parse_param(kw, Lexicon.EDGE, EnumEdge, EnumEdge.CLIP.name)
mirror = parse_param(kw, Lexicon.MIRROR, EnumMirrorMode, EnumMirrorMode.NONE.name)
mirror_pivot = parse_param(kw, Lexicon.PIVOT, EnumConvertType.VEC2, (0.5, 0.5), 0, 1)
tile_xy = parse_param(kw, Lexicon.TILE, EnumConvertType.VEC2, (1., 1.), 1)
proj = parse_param(kw, Lexicon.PROJECTION, EnumProjection, EnumProjection.NORMAL.name)
tltr = parse_param(kw, Lexicon.TLTR, EnumConvertType.VEC4, (0., 0., 1., 0.), 0, 1)
blbr = parse_param(kw, Lexicon.BLBR, EnumConvertType.VEC4, (0., 1., 1., 1.), 0, 1)
strength = parse_param(kw, Lexicon.STRENGTH, EnumConvertType.FLOAT, 1, 0, 1)
mode = parse_param(kw, Lexicon.MODE, EnumScaleMode, EnumScaleMode.MATTE.name)
wihi = parse_param(kw, Lexicon.WH, EnumConvertType.VEC2INT, (512, 512), IMAGE_SIZE_MIN)
sample = parse_param(kw, Lexicon.SAMPLE, EnumInterpolation, EnumInterpolation.LANCZOS4.name)
matte = parse_param(kw, Lexicon.MATTE, EnumConvertType.VEC4INT, (0, 0, 0, 255), 0, 255)
params = list(zip_longest_fill(pA, mask, offset, angle, size, edge, tile_xy, mirror, mirror_pivot, proj, strength, tltr, blbr, mode, wihi, sample, matte))
images = []
pbar = ProgressBar(len(params))
+64 -66
View File
@@ -22,6 +22,9 @@ from cozy_comfyui import \
InputType, EnumConvertType, TensorType, \
deep_merge, parse_dynamic, parse_param
from cozy_comfyui.lexicon import \
Lexicon
from cozy_comfyui.node import \
COZY_TYPE_ANY, \
CozyBaseNode
@@ -83,7 +86,7 @@ class ArrayNode(CozyBaseNode):
)
SORT = 50
DESCRIPTION = """
Processes a batch of data based on the selected mode. Merge, pick, slice, random select, or index items. Can reverse the order of items and divide the data into chunks.
Processes a batch of data based on the selected mode. Merge, pick, slice, random select, or index items. Can also reverse the order of items.
"""
@classmethod
@@ -91,27 +94,26 @@ Processes a batch of data based on the selected mode. Merge, pick, slice, random
d = super().INPUT_TYPES()
d = deep_merge(d, {
"optional": {
"MODE": (EnumBatchMode._member_names_, {
Lexicon.MODE: (EnumBatchMode._member_names_, {
"default": EnumBatchMode.MERGE.name,
"tooltip":"Select a single index, specific range, custom index list or randomized"}),
"RANGE": ("VEC3", {
"tooltip": "Select a single index, specific range, custom index list or randomized"}),
Lexicon.RANGE: ("VEC3", {
"default": (0, 0, 1), "mij": 0, "int": True,
"tooltip":"The start, end and step for the range"}),
"INDEX": ("STRING", {
"tooltip": "The start, end and step for the range"}),
Lexicon.INDEX: ("STRING", {
"default": "",
"tooltip":"Comma separated list of indicies to export"}),
"COUNT": ("INT", {
"tooltip": "Comma separated list of indicies to export"}),
Lexicon.COUNT: ("INT", {
"default": 0, "min": 0, "max": sys.maxsize,
"tooltip":"How many items to return"}),
"REVERSE": ("BOOLEAN", {
"tooltip": "How many items to return"}),
Lexicon.REVERSE: ("BOOLEAN", {
"default": False,
"tooltip":"reverse the calculated output list"}),
"SEED": ("INT", {
"default": 0, "min": 0, "max": sys.maxsize,
"tooltip":"Random seed value"}),
"tooltip": "Reverse the calculated output list"}),
Lexicon.SEED: ("INT", {
"default": 0, "min": 0, "max": sys.maxsize}),
}
})
return d
return Lexicon._parse(d)
@classmethod
def batched(cls, iterable, chunk_size, expand:bool=False, fill:Any=None) -> List[Any]:
@@ -121,13 +123,13 @@ Processes a batch of data based on the selected mode. Merge, pick, slice, random
return [iterable[i: i + chunk_size] for i in range(0, len(iterable), chunk_size)]
def run(self, **kw) -> tuple[int, list]:
data_list = parse_dynamic(kw, "❔", EnumConvertType.ANY, None)
mode = parse_param(kw, "MODE", EnumBatchMode, EnumBatchMode.MERGE.name)[0]
slice_range = parse_param(kw, "RANGE", EnumConvertType.VEC3INT, (0, 0, 1))[0]
index = parse_param(kw, "INDEX", EnumConvertType.STRING, "")[0]
count = parse_param(kw, "COUNT", EnumConvertType.INT, 0, 0, sys.maxsize)[0]
reverse = parse_param(kw, "REVERSE", EnumConvertType.BOOLEAN, False)[0]
seed = parse_param(kw, "SEED", EnumConvertType.INT, 0)[0]
data_list = parse_dynamic(kw, Lexicon.DYNAMIC, EnumConvertType.ANY, None)
mode = parse_param(kw, Lexicon.MODE, EnumBatchMode, EnumBatchMode.MERGE.name)[0]
slice_range = parse_param(kw, Lexicon.RANGE, EnumConvertType.VEC3INT, (0, 0, 1))[0]
index = parse_param(kw, Lexicon.INDEX, EnumConvertType.STRING, "")[0]
count = parse_param(kw, Lexicon.COUNT, EnumConvertType.INT, 0, 0, sys.maxsize)[0]
reverse = parse_param(kw, Lexicon.REVERSE, EnumConvertType.BOOLEAN, False)[0]
seed = parse_param(kw, Lexicon.SEED, EnumConvertType.INT, 0)[0]
data = []
# track latents since they need to be added back to Dict['samples']
@@ -246,7 +248,7 @@ Processes a batch of data based on the selected mode. Merge, pick, slice, random
class QueueBaseNode(CozyBaseNode):
CATEGORY = JOV_CATEGORY
RETURN_TYPES = (COZY_TYPE_ANY, COZY_TYPE_ANY, "STRING", "INT", "INT", "BOOLEAN")
RETURN_NAMES = ("🦄", "QUEUE", "CURRENT", "INDEX", "TOTAL", "TRIGGER", )
RETURN_NAMES = ("❔", "QUEUE", "CURRENT", "INDEX", "TOTAL", "TRIGGER", )
#OUTPUT_IS_LIST = (True, True, True, True, True, True,)
VIDEO_FORMATS = ['.wav', '.mp3', '.webm', '.mp4', '.avi', '.wmv', '.mkv', '.mov', '.mxf']
@@ -259,33 +261,33 @@ class QueueBaseNode(CozyBaseNode):
d = super().INPUT_TYPES()
d = deep_merge(d, {
"optional": {
"Q": ("STRING", {
Lexicon.QUEUE: ("STRING", {
"default": "./res/img/test-a.png", "multiline": True,
"tooltip": "Current items to process during Queue iteration."}),
"RECURSE": ("BOOLEAN", {
"tooltip": "Current items to process during Queue iteration"}),
Lexicon.RECURSE: ("BOOLEAN", {
"default": False,
"tooltip":"Recurse through all subdirectories found"}),
"BATCH": ("BOOLEAN", {
"tooltip": "Recurse through all subdirectories found"}),
Lexicon.BATCH: ("BOOLEAN", {
"default": False,
"tooltip":"Load all items, if they are loadable items, i.e. batch load images from the Queue's list."}),
"SELECT": ("INT", {
"tooltip": "Load all items, if they are loadable items, i.e. batch load images from the Queue's list"}),
Lexicon.SELECT: ("INT", {
"default": 0, "min": 0,
"tooltip": "What index to use for the current queue item. 0 will move to the next item each queue run"}),
"HOLD": ("BOOLEAN", {
"tooltip": "The index to use for the current queue item. 0 will move to the next item each queue run"}),
Lexicon.HOLD: ("BOOLEAN", {
"default": False,
"tooltip":"Hold the item at the current queue index"}),
"STOP": ("BOOLEAN", {
"tooltip": "Hold the item at the current queue index"}),
Lexicon.STOP: ("BOOLEAN", {
"default": False,
"tooltip":"When the Queue is out of items, send a `HALT` to ComfyUI."}),
"LOOP": ("BOOLEAN", {
"tooltip": "When the Queue is out of items, send a `HALT` to ComfyUI"}),
Lexicon.LOOP: ("BOOLEAN", {
"default": True,
"tooltip":"If the queue should loop. If `False` and if there are more iterations, will send the previous image."}),
"RESET": ("BOOLEAN", {
"tooltip": "If the queue should loop. If `False` and if there are more iterations, will send the previous image"}),
Lexicon.RESET: ("BOOLEAN", {
"default": False,
"tooltip":"Reset the queue back to index 1"}),
"tooltip": "Reset the queue back to index 1"}),
}
})
return d
return Lexicon._parse(d)
def __init__(self) -> None:
self.__index = 0
@@ -368,26 +370,26 @@ class QueueBaseNode(CozyBaseNode):
self.__ident = ident
# should work headless as well
if (new_val := parse_param(kw, "SELECT", EnumConvertType.INT, 0)[0]) > 0:
if (new_val := parse_param(kw, Lexicon.SELECT, EnumConvertType.INT, 0)[0]) > 0:
self.__index = new_val - 1
reset = parse_reset(ident) > 0
if reset or parse_param(kw, "RESET", EnumConvertType.BOOLEAN, False)[0]:
if reset or parse_param(kw, Lexicon.RESET, EnumConvertType.BOOLEAN, False)[0]:
self.__q = None
self.__index = 0
mode = parse_param(kw, "MODE", EnumScaleMode, EnumScaleMode.MATTE.name)[0]
sample = parse_param(kw, "SAMPLE", EnumInterpolation, EnumInterpolation.LANCZOS4.name)[0]
wihi = parse_param(kw, "WH", EnumConvertType.VEC2INT, (512, 512), IMAGE_SIZE_MIN)[0]
mode = parse_param(kw, Lexicon.MODE, EnumScaleMode, EnumScaleMode.MATTE.name)[0]
sample = parse_param(kw, Lexicon.SAMPLE, EnumInterpolation, EnumInterpolation.LANCZOS4.name)[0]
wihi = parse_param(kw, Lexicon.WH, EnumConvertType.VEC2INT, (512, 512), IMAGE_SIZE_MIN)[0]
w, h = wihi
matte = parse_param(kw, "MATTE", EnumConvertType.VEC4INT, (0, 0, 0, 255), 0, 255)[0]
matte = parse_param(kw, Lexicon.MATTE, EnumConvertType.VEC4INT, (0, 0, 0, 255), 0, 255)[0]
if self.__q is None:
# process Q into ...
# check if folder first, file, then string.
# entry is: data, <filter if folder:*.png,*.jpg>, <repeats:1+>
recurse = parse_param(kw, "RECURSE", EnumConvertType.BOOLEAN, False)[0]
q = parse_param(kw, "Q", EnumConvertType.STRING, "")[0]
recurse = parse_param(kw, Lexicon.RECURSE, EnumConvertType.BOOLEAN, False)[0]
q = parse_param(kw, Lexicon.QUEUE, EnumConvertType.STRING, "")[0]
self.__q = self.__parseQ(q, recurse)
self.__len = len(self.__q)
self.__index_last = 0
@@ -396,17 +398,17 @@ class QueueBaseNode(CozyBaseNode):
self.__previous = self.process(self.__previous)
# make sure we have more to process if are a single fire queue
stop = parse_param(kw, "STOP", EnumConvertType.BOOLEAN, False)[0]
stop = parse_param(kw, Lexicon.STOP, EnumConvertType.BOOLEAN, False)[0]
if stop and self.__index >= self.__len:
comfy_api_post("jovi-queue-done", ident, self.status)
interrupt_processing()
return self.__previous, self.__q, self.__current, self.__index_last+1, self.__len
if (wait := parse_param(kw, "HOLD", EnumConvertType.BOOLEAN, False))[0] == True:
if (wait := parse_param(kw, Lexicon.HOLD, EnumConvertType.BOOLEAN, False))[0] == True:
self.__index = self.__index_last
# otherwise loop around the end
loop = parse_param(kw, "LOOP", EnumConvertType.BOOLEAN, False)[0]
loop = parse_param(kw, Lexicon.LOOP, EnumConvertType.BOOLEAN, False)[0]
if loop == True:
self.__index %= self.__len
else:
@@ -417,7 +419,7 @@ class QueueBaseNode(CozyBaseNode):
self.__index_last = self.__index
info = f"QUEUE #{ident} [{self.__current}] ({self.__index})"
batched = False
if (batched := parse_param(kw, "BATCH", EnumConvertType.BOOLEAN, False)[0]) == True:
if (batched := parse_param(kw, Lexicon.BATCH, EnumConvertType.BOOLEAN, False)[0]) == True:
data = []
mw, mh, mc = 0, 0, 0
for idx in range(self.__len):
@@ -506,30 +508,26 @@ Manage a queue of specific items: media files. Supports various image and video
d = super().INPUT_TYPES()
d = deep_merge(d, {
"optional": {
"MODE": (EnumScaleMode._member_names_, {
"default": EnumScaleMode.MATTE.name,
"tooltip": "If the image should be resized to fit within given dimensions or keep the original size"}),
"WH": ("VEC2", {
Lexicon.MODE: (EnumScaleMode._member_names_, {
"default": EnumScaleMode.MATTE.name}),
Lexicon.WH: ("VEC2", {
"default": (512, 512), "mij":IMAGE_SIZE_MIN, "int": True,
"label": ["W", "H"],
"tooltip": "Width and Height"}),
"SAMPLE": (EnumInterpolation._member_names_, {
"default": EnumInterpolation.LANCZOS4.name,
"tooltip": "Sampling method for resizing images"}),
"MATTE": ("VEC4", {
"default": (0, 0, 0, 255), "rgb": True,
"tooltip": "Background color for padding"}),
"label": ["W", "H"],}),
Lexicon.SAMPLE: (EnumInterpolation._member_names_, {
"default": EnumInterpolation.LANCZOS4.name,}),
Lexicon.MATTE: ("VEC4", {
"default": (0, 0, 0, 255), "rgb": True,}),
},
"hidden": d.get("hidden", {})
})
return d
return Lexicon._parse(d)
def run(self, ident, **kw) -> tuple[TensorType, TensorType, TensorType, str, int, int, bool]:
data, _, current, index, total, trigger = super().run(ident, **kw)
if not isinstance(data, (TensorType, )):
data = [None, None, None]
else:
matte = parse_param(kw, "MATTE", EnumConvertType.VEC4INT, (0, 0, 0, 255), 0, 255)[0]
matte = parse_param(kw, Lexicon.MATTE, EnumConvertType.VEC4INT, (0, 0, 0, 255), 0, 255)[0]
data = [tensor_to_cv(d) for d in data]
data = [cv_to_tensor_full(d, matte) for d in data]
data = [torch.stack(d) for d in zip(*data)]
+15 -15
View File
@@ -14,6 +14,9 @@ from cozy_comfyui import \
InputType, EnumConvertType, TensorType, \
deep_merge, parse_dynamic, parse_param
from cozy_comfyui.lexicon import \
Lexicon
from cozy_comfyui.node import \
COZY_TYPE_IMAGE, \
CozyBaseNode
@@ -155,19 +158,18 @@ Visualize a series of data points over time. It accepts a dynamic number of valu
d = super().INPUT_TYPES()
d = deep_merge(d, {
"optional": {
"RESET": ("BOOLEAN", {
Lexicon.RESET: ("BOOLEAN", {
"default": False,
"tooltip":"Clear the graph history"}),
"VAL": ("INT", {
Lexicon.VALUE: ("INT", {
"default": 60, "min": 0,
"tooltip":"Number of values to graph and display"}),
"WH": ("VEC2", {
Lexicon.WH: ("VEC2", {
"default": (512, 512), "mij":IMAGE_SIZE_MIN, "int": True,
"label": ["W", "H"],
"tooltip":"Width and Height of the graph output"}),
"label": ["W", "H"]}),
}
})
return d
return Lexicon._parse(d)
@classmethod
def IS_CHANGED(cls) -> float:
@@ -179,12 +181,12 @@ Visualize a series of data points over time. It accepts a dynamic number of valu
self.__fig, self.__ax = plt.subplots(figsize=(5.12, 5.12))
def run(self, ident, **kw) -> tuple[TensorType]:
slice = parse_param(kw, "VAL", EnumConvertType.INT, 60)[0]
wihi = parse_param(kw, "WH", EnumConvertType.VEC2INT, (512, 512), 1)[0]
if parse_reset(ident) > 0 or parse_param(kw, "RESET", EnumConvertType.BOOLEAN, False)[0]:
slice = parse_param(kw, Lexicon.VALUE, EnumConvertType.INT, 60)[0]
wihi = parse_param(kw, Lexicon.WH, EnumConvertType.VEC2INT, (512, 512), 1)[0]
if parse_reset(ident) > 0 or parse_param(kw, Lexicon.RESET, EnumConvertType.BOOLEAN, False)[0]:
self.__history = []
longest_edge = 0
dynamic = parse_dynamic(kw, "❔", EnumConvertType.FLOAT, 0)
dynamic = parse_dynamic(kw, Lexicon.DYNAMIC, EnumConvertType.FLOAT, 0)
dynamic = [i[0] for i in dynamic]
self.__ax.clear()
for idx, val in enumerate(dynamic):
@@ -236,14 +238,12 @@ Exports and Displays immediate information about images.
d = super().INPUT_TYPES()
d = deep_merge(d, {
"optional": {
"IMAGE": (COZY_TYPE_IMAGE, {
"default": None,
"tooltip":"The image to examine"})
Lexicon.IMAGE: (COZY_TYPE_IMAGE, {})
}
})
return d
return Lexicon._parse(d)
def run(self, **kw) -> tuple[int, list]:
image = parse_param(kw, "IMAGE", EnumConvertType.IMAGE, None)
image = parse_param(kw, Lexicon.IMAGE, EnumConvertType.IMAGE, None)
height, width, cc = image[0].shape
return (len(image), width, height, cc, (width, height), (width, height, cc))
+61 -70
View File
@@ -20,6 +20,9 @@ from cozy_comfyui import \
InputType, EnumConvertType, \
deep_merge, parse_param, parse_param_list, zip_longest_fill
from cozy_comfyui.lexicon import \
Lexicon
from cozy_comfyui.node import \
COZY_TYPE_IMAGE, COZY_TYPE_ANY, \
CozyBaseNode
@@ -99,30 +102,30 @@ Introduce pauses in the workflow that accept an optional input to pass through a
d = super().INPUT_TYPES()
d = deep_merge(d, {
"optional": {
"IN": (COZY_TYPE_ANY, {
Lexicon.PASS_IN: (COZY_TYPE_ANY, {
"default": None,
"tooltip":"The data that should be held until the timer completes."}),
"TIMER": ("INT", {
Lexicon.TIMER: ("INT", {
"default" : 0, "min": -1,
"tooltip":"How long to delay if enabled. 0 means no delay."}),
"ENABLE": ("BOOLEAN", {
Lexicon.ENABLE: ("BOOLEAN", {
"default": True,
"tooltip":"Enable or disable the screensaver."})
}
})
return d
return Lexicon._parse(d)
@classmethod
def IS_CHANGED(cls, **kw) -> float:
return float("NaN")
def run(self, ident, **kw) -> tuple[Any]:
delay = parse_param(kw, "TIMER", EnumConvertType.INT, -1, 0, JOV_DELAY_MAX)[0]
delay = parse_param(kw, Lexicon.TIMER, EnumConvertType.INT, -1, 0, JOV_DELAY_MAX)[0]
if delay < 0:
delay = JOV_DELAY_MAX
if delay > JOV_DELAY_MIN:
comfy_api_post("jovi-delay-user", ident, {"id": ident, "timeout": delay})
# enable = parse_param(kw, "ENABLE", EnumConvertType.BOOLEAN, True)
# enable = parse_param(kw, Lexicon.ENABLE, EnumConvertType.BOOLEAN, True)[0]
step = 1
pbar = ProgressBar(delay)
@@ -139,7 +142,7 @@ Introduce pauses in the workflow that accept an optional input to pass through a
logger.info(f"delay [continue] ({step}): {ident}")
pbar.update_absolute(step)
step += 1
return kw["IN"],
return kw[Lexicon.PASS_IN],
class ExportNode(CozyBaseNode):
NAME = "EXPORT (JOV) 📽"
@@ -156,52 +159,45 @@ Responsible for saving images or animations to disk. It supports various output
d = super().INPUT_TYPES()
d = deep_merge(d, {
"optional": {
"IMAGE": (COZY_TYPE_IMAGE, {
"tooltip": "Pixel Data (RGBA, RGB or Grayscale)"
}),
"OUT": ("STRING", {
Lexicon.IMAGE: (COZY_TYPE_IMAGE, {}),
Lexicon.PATH: ("STRING", {
"default": get_output_directory(),
"default_top":"<comfy output dir>",
"tooltip":"Pass through another route node to pre-populate the outputs."}),
"FORMAT": (FORMATS, {
"default": FORMATS[0],
"tooltip":"Pass through another route node to pre-populate the outputs."}),
"PREFIX": ("STRING", {
"default": "jovi",
"tooltip":"Pass through another route node to pre-populate the outputs."}),
"OVERWRITE": ("BOOLEAN", {
"default": False,
"tooltip":"Pass through another route node to pre-populate the outputs."}),
"default_top": "<comfy output dir>",}),
Lexicon.FORMAT: (FORMATS, {
"default": FORMATS[0],}),
Lexicon.PREFIX: ("STRING", {
"default": "jovi",}),
Lexicon.OVERWRITE: ("BOOLEAN", {
"default": False,}),
# GIF ONLY
"OPT": ("BOOLEAN", {
"default": False,
"tooltip":"Pass through another route node to pre-populate the outputs."}),
Lexicon.OPTIMIZE: ("BOOLEAN", {
"default": False,}),
# GIFSKI ONLY
"QUALITY": ("INT", {"default": 90, "min": 1, "max": 100,
"tooltip":"Pass through another route node to pre-populate the outputs."}),
"QUALITY_M": ("INT", {"default": 100, "min": 1, "max": 100,
"tooltip":"Pass through another route node to pre-populate the outputs."}),
Lexicon.QUALITY: ("INT", {
"default": 90, "min": 1, "max": 100,}),
Lexicon.QUALITY_M: ("INT", {
"default": 100, "min": 1, "max": 100,}),
# GIF OR GIFSKI
"FPS": ("INT", {"default": 24, "min": 1, "max": 60,
"tooltip":"Pass through another route node to pre-populate the outputs."}),
Lexicon.FPS: ("INT", {
"default": 24, "min": 1, "max": 60,}),
# GIF OR GIFSKI
"LOOP": ("INT", {"default": 0, "min": 0,
"tooltip":"Pass through another route node to pre-populate the outputs."}),
Lexicon.LOOP: ("INT", {
"default": 0, "min": 0,}),
}
})
return d
return Lexicon._parse(d)
def run(self, **kw) -> None:
images = parse_param(kw, "IMAGE", EnumConvertType.IMAGE, None)
suffix = parse_param(kw, "PREFIX", EnumConvertType.STRING, uuid4().hex[:16])[0]
output_dir = parse_param(kw, "OUT", EnumConvertType.STRING, "")[0]
format = parse_param(kw, "FORMAT", EnumConvertType.STRING, "gif")[0]
overwrite = parse_param(kw, "OVERWRITE", EnumConvertType.BOOLEAN, False)[0]
optimize = parse_param(kw, "OPT", EnumConvertType.BOOLEAN, False)[0]
quality = parse_param(kw, "QUALITY", EnumConvertType.INT, 90, 0, 100)[0]
motion = parse_param(kw, "QUALITY_M", EnumConvertType.INT, 100, 0, 100)[0]
fps = parse_param(kw, "FPS", EnumConvertType.INT, 24, 1, 60)[0]
loop = parse_param(kw, "LOOP", EnumConvertType.INT, 0, 0)[0]
images = parse_param(kw, Lexicon.IMAGE, EnumConvertType.IMAGE, None)
suffix = parse_param(kw, Lexicon.PREFIX, EnumConvertType.STRING, uuid4().hex[:16])[0]
output_dir = parse_param(kw, Lexicon.PATH, EnumConvertType.STRING, "")[0]
format = parse_param(kw, Lexicon.FORMAT, EnumConvertType.STRING, "gif")[0]
overwrite = parse_param(kw, Lexicon.OVERWRITE, EnumConvertType.BOOLEAN, False)[0]
optimize = parse_param(kw, Lexicon.OPTIMIZE, EnumConvertType.BOOLEAN, False)[0]
quality = parse_param(kw, Lexicon.QUALITY, EnumConvertType.INT, 90, 0, 100)[0]
motion = parse_param(kw, Lexicon.QUALITY_M, EnumConvertType.INT, 100, 0, 100)[0]
fps = parse_param(kw, Lexicon.FPS, EnumConvertType.INT, 24, 1, 60)[0]
loop = parse_param(kw, Lexicon.LOOP, EnumConvertType.INT, 0, 0)[0]
output_dir = Path(output_dir)
output_dir.mkdir(parents=True, exist_ok=True)
@@ -273,16 +269,17 @@ Routes the input data from the optional input ports to the output port, preservi
d = super().INPUT_TYPES()
e = {
"optional": {
"ROUTE": ("BUS", {"default": None, "tooltip":"Pass through another route node to pre-populate the outputs."}),
Lexicon.ROUTE: ("BUS", {
"default": None,}),
}
}
d = deep_merge(d, e)
return d
return Lexicon._parse(d)
def run(self, **kw) -> tuple[Any, ...]:
inout = parse_param(kw, "ROUTE", EnumConvertType.ANY, None)
inout = parse_param(kw, Lexicon.ROUTE, EnumConvertType.ANY, None)
vars = kw.copy()
vars.pop("ROUTE", None)
vars.pop(Lexicon.ROUTE, None)
vars.pop('ident', None)
parsed = []
@@ -300,7 +297,7 @@ class SaveOutputNode(CozyBaseNode):
RETURN_TYPES = ()
SORT = 85
DESCRIPTION = """
Save the output image along with its metadata to the specified path. Supports saving additional user metadata and prompt information.
Save images with metadata to any specified path. Can save user metadata and prompt information.
"""
@classmethod
@@ -308,31 +305,25 @@ Save the output image along with its metadata to the specified path. Supports sa
d = super().INPUT_TYPES(True, True)
d = deep_merge(d, {
"optional": {
"IMAGE": ("IMAGE", {
"default": None,
"tooltip":""}),
"PATH": ("STRING", {
"default": "", "dynamicPrompts":False,
"tooltip":"Destination path to save the output"}),
"NAME": ("STRING", {
"default": "output", "dynamicPrompts":False,
"tooltip":"Filename of the output"}),
"META": ("JSON", {
"default": None,
"tooltip":"Extra metadata to save in the file"}),
"USER": ("STRING", {
"default": "", "multiline": True, "dynamicPrompts":False,
"tooltip":"Custom user metadat to save with the file"}),
Lexicon.IMAGE: ("IMAGE", {}),
Lexicon.PATH: ("STRING", {
"default": "", "dynamicPrompts":False}),
Lexicon.NAME: ("STRING", {
"default": "output", "dynamicPrompts":False,}),
Lexicon.META: ("JSON", {
"default": None,}),
Lexicon.USER: ("STRING", {
"default": "", "multiline": True, "dynamicPrompts":False,}),
}
})
return d
return Lexicon._parse(d)
def run(self, **kw) -> dict[str, Any]:
image = parse_param(kw, 'IMAGE', EnumConvertType.IMAGE, None)
path = parse_param(kw, 'PATH', EnumConvertType.STRING, "")
fname = parse_param(kw, 'NAME', EnumConvertType.STRING, "output")
metadata = parse_param(kw, 'META', EnumConvertType.DICT, {})
usermeta = parse_param(kw, 'USER', EnumConvertType.DICT, {})
image = parse_param(kw, Lexicon.IMAGE, EnumConvertType.IMAGE, None)
path = parse_param(kw, Lexicon.PATH, EnumConvertType.STRING, "")
fname = parse_param(kw, Lexicon.NAME, EnumConvertType.STRING, "output")
metadata = parse_param(kw, Lexicon.META, EnumConvertType.DICT, {})
usermeta = parse_param(kw, Lexicon.USER, EnumConvertType.DICT, {})
prompt = parse_param(kw, 'prompt', EnumConvertType.STRING, "")
pnginfo = parse_param(kw, 'extra_pnginfo', EnumConvertType.DICT, {})
params = list(zip_longest_fill(image, path, fname, metadata, usermeta, prompt, pnginfo))
+80 -126
View File
@@ -9,10 +9,16 @@ from cozy_comfyui import \
InputType, EnumConvertType, \
deep_merge, parse_param, parse_value, zip_longest_fill
from cozy_comfyui.lexicon import \
Lexicon
from cozy_comfyui.node import \
COZY_TYPE_ANY, COZY_TYPE_NUMERICAL, COZY_TYPE_NUMBER, \
CozyBaseNode
from . import \
EnumFillOperation
JOV_CATEGORY = "VARIABLE"
# ==============================================================================
@@ -23,7 +29,8 @@ class ValueNode(CozyBaseNode):
NAME = "VALUE (JOV) 🧬"
CATEGORY = JOV_CATEGORY
RETURN_TYPES = (COZY_TYPE_ANY, COZY_TYPE_ANY, COZY_TYPE_ANY, COZY_TYPE_ANY, COZY_TYPE_ANY,)
RETURN_NAMES = ("🦄", "X", "Y", "Z", "W",)
RETURN_NAMES = ("❔", Lexicon.X, Lexicon.Y, Lexicon.Z, Lexicon.W,)
OUTPUT_IS_LIST = (True, True, True, True, True,)
SORT = 5
DESCRIPTION = """
Supplies raw or default values for various data types, supporting vector input with components for X, Y, Z, and W. It also provides a string input option.
@@ -36,55 +43,53 @@ Supplies raw or default values for various data types, supporting vector input w
typ = EnumConvertType._member_names_[:6]
d = deep_merge(d, {
"optional": {
"A": (COZY_TYPE_ANY, {
"default": None,
"tooltip":"Passes a raw value directly, or supplies defaults for any value inputs without connections"}),
"TYPE": (typ, {
"default": EnumConvertType.BOOLEAN.name,
"tooltip":"Take the input and convert it into the selected type."}),
"X": (COZY_TYPE_NUMERICAL, {
Lexicon.IN_A: (COZY_TYPE_ANY, {
"default": None,}),
Lexicon.X: (COZY_TYPE_NUMERICAL, {
"default": 0, "mij": -sys.maxsize, "maj": sys.maxsize,
"forceInput": True}),
"Y": (COZY_TYPE_NUMERICAL, {
Lexicon.Y: (COZY_TYPE_NUMERICAL, {
"default": 0, "mij": -sys.maxsize, "maj": sys.maxsize,
"forceInput": True}),
"Z": (COZY_TYPE_NUMERICAL, {
Lexicon.Z: (COZY_TYPE_NUMERICAL, {
"default": 0, "mij": -sys.maxsize, "maj": sys.maxsize,
"forceInput": True}),
"W": (COZY_TYPE_NUMERICAL, {
Lexicon.W: (COZY_TYPE_NUMERICAL, {
"default": 0, "mij": -sys.maxsize, "maj": sys.maxsize,
"forceInput": True}),
"AA": ("VEC4", {
Lexicon.TYPE: (typ, {
"default": EnumConvertType.BOOLEAN.name}),
Lexicon.DEFAULT_A: ("VEC4", {
"default": (0, 0, 0, 0), #"mij": -sys.maxsize, "maj": sys.maxsize,
"label": ["X", "Y"],
"tooltip":"default value vector for A"}),
"BB": ("VEC4", {
"label": [Lexicon.X, Lexicon.Y, Lexicon.Z, Lexicon.W]}),
Lexicon.DEFAULT_B: ("VEC4", {
"default": (1,1,1,1), #"mij": -sys.maxsize, "maj": sys.maxsize,
"label": ["X", "Y", "Z", "W"],
"tooltip":"default value vector for B"}),
"SEED": ("INT", {
"label": [Lexicon.X, Lexicon.Y, Lexicon.Z, Lexicon.W]}),
Lexicon.FILL: (EnumFillOperation._member_names_, {
"default": EnumFillOperation.DEFAULT.name}),
Lexicon.SEED: ("INT", {
"default": 0, "min": 0, "max": sys.maxsize}),
}
})
return d
return Lexicon._parse(d)
def run(self, **kw) -> tuple[bool]:
raw = parse_param(kw, "A", EnumConvertType.ANY, 0)
r_x = parse_param(kw, "X", EnumConvertType.FLOAT, None, -sys.maxsize, sys.maxsize)
r_y = parse_param(kw, "Y", EnumConvertType.FLOAT, None, -sys.maxsize, sys.maxsize)
r_z = parse_param(kw, "Z", EnumConvertType.FLOAT, None, -sys.maxsize, sys.maxsize)
r_w = parse_param(kw, "W", EnumConvertType.FLOAT, None, -sys.maxsize, sys.maxsize)
typ = parse_param(kw, "TYPE", EnumConvertType, EnumConvertType.BOOLEAN.name)
xyzw = parse_param(kw, "AA", EnumConvertType.VEC4, (0, 0, 0, 0))
seed = parse_param(kw, "SEED", EnumConvertType.INT, 0, 0)
yyzw = parse_param(kw, "BB", EnumConvertType.VEC4, (1, 1, 1, 1))
x_str = parse_param(kw, "STRING", EnumConvertType.STRING, "")
params = list(zip_longest_fill(raw, r_x, r_y, r_z, r_w, typ, xyzw, seed, yyzw, x_str))
raw = parse_param(kw, Lexicon.IN_A, EnumConvertType.ANY, 0)
r_x = parse_param(kw, Lexicon.X, EnumConvertType.FLOAT, None, -sys.maxsize, sys.maxsize)
r_y = parse_param(kw, Lexicon.Y, EnumConvertType.FLOAT, None, -sys.maxsize, sys.maxsize)
r_z = parse_param(kw, Lexicon.Z, EnumConvertType.FLOAT, None, -sys.maxsize, sys.maxsize)
r_w = parse_param(kw, Lexicon.W, EnumConvertType.FLOAT, None, -sys.maxsize, sys.maxsize)
typ = parse_param(kw, Lexicon.TYPE, EnumConvertType, EnumConvertType.BOOLEAN.name)
xyzw = parse_param(kw, Lexicon.DEFAULT_A, EnumConvertType.VEC4, (0, 0, 0, 0))
yyzw = parse_param(kw, Lexicon.DEFAULT_B, EnumConvertType.VEC4, (1, 1, 1, 1))
fill = parse_param(kw, Lexicon.FILL, EnumConvertType.BOOLEAN, False)
seed = parse_param(kw, Lexicon.SEED, EnumConvertType.INT, 0, 0)
params = list(zip_longest_fill(raw, r_x, r_y, r_z, r_w, typ, xyzw, yyzw, fill, seed))
results = []
pbar = ProgressBar(len(params))
old_seed = -1
for idx, (raw, r_x, r_y, r_z, r_w, typ, xyzw, seed, yyzw, x_str) in enumerate(params):
default = [x_str]
for idx, (raw, r_x, r_y, r_z, r_w, typ, xyzw, yyzw, fill, seed) in enumerate(params):
# default = [x_str]
default2 = None
a, b, c, d = xyzw
a2, b2, c2, d2 = yyzw
@@ -126,6 +131,7 @@ Supplies raw or default values for various data types, supporting vector input w
items[i] = out[i]
results.append([out, *items])
pbar.update_absolute(idx)
if len(results) < 2:
return results[0]
return *list(zip(*results)),
@@ -149,34 +155,28 @@ Outputs a VECTOR2.
d = super().INPUT_TYPES()
d = deep_merge(d, {
"optional": {
"X": (COZY_TYPE_NUMBER, {
Lexicon.X: (COZY_TYPE_NUMBER, {
"min": -sys.maxsize, "max": sys.maxsize,
"tooltip": "X channel value"}),
"Y": (COZY_TYPE_NUMBER, {
Lexicon.Y: (COZY_TYPE_NUMBER, {
"min": -sys.maxsize, "max": sys.maxsize,
"tooltip": "Y channel value"}),
"A": ("FLOAT", {
"default": 0, "min": -sys.maxsize, "max": sys.maxsize,
"tooltip": "Default X channel value"}),
"B": ("FLOAT", {
"default": 0, "min": -sys.maxsize, "max": sys.maxsize,
"tooltip": "Default Y channel value"}),
Lexicon.DEFAULT: ("VEC2", {
"default": 0, "min": -sys.maxsize, "max": sys.maxsize,}),
}
})
return d
return Lexicon._parse(d)
def run(self, **kw) -> tuple[tuple[float, ...], tuple[int, ...]]:
x = parse_param(kw, "X", EnumConvertType.FLOAT, None, -sys.maxsize, sys.maxsize)
y = parse_param(kw, "Y", EnumConvertType.FLOAT, None, -sys.maxsize, sys.maxsize)
a = parse_param(kw, "A", EnumConvertType.FLOAT, 0, -sys.maxsize, sys.maxsize)
b = parse_param(kw, "B", EnumConvertType.FLOAT, 0, -sys.maxsize, sys.maxsize)
x = parse_param(kw, Lexicon.X, EnumConvertType.FLOAT, None, -sys.maxsize, sys.maxsize)
y = parse_param(kw, Lexicon.Y, EnumConvertType.FLOAT, None, -sys.maxsize, sys.maxsize)
default = parse_param(kw, Lexicon.DEFAULT, EnumConvertType.VEC2, 0, -sys.maxsize, sys.maxsize)
result = []
params = list(zip_longest_fill(x, y, a, b))
params = list(zip_longest_fill(x, y, default))
pbar = ProgressBar(len(params))
for idx, (x, y, a, b) in enumerate(params):
x = round(a, 9) if x is None else round(x, 9)
y = round(b, 9) if y is None else round(y, 9)
for idx, (x, y, default) in enumerate(params):
x = round(default[0], 9) if x is None else round(x, 9)
y = round(default[1], 9) if y is None else round(y, 9)
result.append((x, y,))
pbar.update_absolute(idx)
return result,
@@ -200,42 +200,34 @@ Outputs a VECTOR3.
d = super().INPUT_TYPES()
d = deep_merge(d, {
"optional": {
"X": (COZY_TYPE_NUMBER, {
Lexicon.X: (COZY_TYPE_NUMBER, {
"min": -sys.maxsize, "max": sys.maxsize,
"tooltip": "X channel value"}),
"Y": (COZY_TYPE_NUMBER, {
Lexicon.Y: (COZY_TYPE_NUMBER, {
"min": -sys.maxsize, "max": sys.maxsize,
"tooltip": "Y channel value"}),
"Z": (COZY_TYPE_NUMBER, {
Lexicon.Z: (COZY_TYPE_NUMBER, {
"min": -sys.maxsize, "max": sys.maxsize,
"tooltip": "Z channel value"}),
"A": ("FLOAT", {
Lexicon.DEFAULT: ("VEC3", {
"default": 0, "min": -sys.maxsize, "max": sys.maxsize,
"tooltip": "Default X channel value"}),
"B": ("FLOAT", {
"default": 0, "min": -sys.maxsize, "max": sys.maxsize,
"tooltip": "Default Y channel value"}),
"C": ("FLOAT", {
"default": 0, "min": -sys.maxsize, "max": sys.maxsize,
"tooltip": "Default Z channel value"}),
}
})
return d
return Lexicon._parse(d)
def run(self, **kw) -> tuple[tuple[float, ...], tuple[int, ...]]:
x = parse_param(kw, "X", EnumConvertType.FLOAT, None, -sys.maxsize, sys.maxsize)
y = parse_param(kw, "Y", EnumConvertType.FLOAT, None, -sys.maxsize, sys.maxsize)
z = parse_param(kw, "Z", EnumConvertType.FLOAT, None, -sys.maxsize, sys.maxsize)
a = parse_param(kw, "A", EnumConvertType.FLOAT, 0, -sys.maxsize, sys.maxsize)
b = parse_param(kw, "B", EnumConvertType.FLOAT, 0, -sys.maxsize, sys.maxsize)
c = parse_param(kw, "C", EnumConvertType.FLOAT, 0, -sys.maxsize, sys.maxsize)
x = parse_param(kw, Lexicon.X, EnumConvertType.FLOAT, None, -sys.maxsize, sys.maxsize)
y = parse_param(kw, Lexicon.Y, EnumConvertType.FLOAT, None, -sys.maxsize, sys.maxsize)
z = parse_param(kw, Lexicon.Z, EnumConvertType.FLOAT, None, -sys.maxsize, sys.maxsize)
default = parse_param(kw, Lexicon.DEFAULT, EnumConvertType.VEC3, 0, -sys.maxsize, sys.maxsize)
result = []
params = list(zip_longest_fill(x, y, z, a, b, c))
params = list(zip_longest_fill(x, y, z, default))
pbar = ProgressBar(len(params))
for idx, (x, y, z, a, b, c) in enumerate(params):
x = round(a, 9) if x is None else round(x, 9)
y = round(b, 9) if y is None else round(y, 9)
z = round(c, 9) if z is None else round(z, 9)
for idx, (x, y, z, default) in enumerate(params):
x = round(default[0], 9) if x is None else round(x, 9)
y = round(default[1], 9) if y is None else round(y, 9)
z = round(default[2], 9) if z is None else round(z, 9)
result.append((x, y, z,))
pbar.update_absolute(idx)
return result,
@@ -259,76 +251,38 @@ Outputs a VEC4.
d = super().INPUT_TYPES()
d = deep_merge(d, {
"optional": {
"X": (COZY_TYPE_NUMBER, {
Lexicon.X: (COZY_TYPE_NUMBER, {
"min": -sys.maxsize, "max": sys.maxsize,
"tooltip": "X channel value"}),
"Y": (COZY_TYPE_NUMBER, {
Lexicon.Y: (COZY_TYPE_NUMBER, {
"min": -sys.maxsize, "max": sys.maxsize,
"tooltip": "Y channel value"}),
"Z": (COZY_TYPE_NUMBER, {
Lexicon.Z: (COZY_TYPE_NUMBER, {
"min": -sys.maxsize, "max": sys.maxsize,
"tooltip": "Z channel value"}),
"W": (COZY_TYPE_NUMBER, {
Lexicon.W: (COZY_TYPE_NUMBER, {
"min": -sys.maxsize, "max": sys.maxsize,
"tooltip": "W channel value"}),
"A": ("FLOAT", {
"default": 0, "min": -sys.maxsize, "max": sys.maxsize,
"tooltip": "Default X channel value"}),
"B": ("FLOAT", {
"default": 0, "min": -sys.maxsize, "max": sys.maxsize,
"tooltip": "Default Y channel value"}),
"C": ("FLOAT", {
"default": 0, "min": -sys.maxsize, "max": sys.maxsize,
"tooltip": "Default Z channel value"}),
"D": ("FLOAT", {
"default": 0, "min": -sys.maxsize, "max": sys.maxsize,
"tooltip": "Default W channel value"}),
Lexicon.DEFAULT: ("VEC4", {
"default": 0, "min": -sys.maxsize, "max": sys.maxsize,}),
}
})
return d
return Lexicon._parse(d)
def run(self, **kw) -> tuple[tuple[float, ...], tuple[int, ...]]:
x = parse_param(kw, "X", EnumConvertType.FLOAT, None, -sys.maxsize, sys.maxsize)
y = parse_param(kw, "Y", EnumConvertType.FLOAT, None, -sys.maxsize, sys.maxsize)
z = parse_param(kw, "Z", EnumConvertType.FLOAT, None, -sys.maxsize, sys.maxsize)
w = parse_param(kw, "W", EnumConvertType.FLOAT, None, -sys.maxsize, sys.maxsize)
a = parse_param(kw, "A", EnumConvertType.FLOAT, 0, -sys.maxsize, sys.maxsize)
b = parse_param(kw, "B", EnumConvertType.FLOAT, 0, -sys.maxsize, sys.maxsize)
c = parse_param(kw, "C", EnumConvertType.FLOAT, 0, -sys.maxsize, sys.maxsize)
d = parse_param(kw, "D", EnumConvertType.FLOAT, 0, -sys.maxsize, sys.maxsize)
x = parse_param(kw, Lexicon.X, EnumConvertType.FLOAT, None, -sys.maxsize, sys.maxsize)
y = parse_param(kw, Lexicon.Y, EnumConvertType.FLOAT, None, -sys.maxsize, sys.maxsize)
z = parse_param(kw, Lexicon.Z, EnumConvertType.FLOAT, None, -sys.maxsize, sys.maxsize)
w = parse_param(kw, Lexicon.W, EnumConvertType.FLOAT, None, -sys.maxsize, sys.maxsize)
default = parse_param(kw, Lexicon.DEFAULT, EnumConvertType.VEC4, 0, -sys.maxsize, sys.maxsize)
result = []
params = list(zip_longest_fill(x, y, z, w, a, b, c, d))
pbar = ProgressBar(len(params))
for idx, (x, y, z, w, a, b, c, d) in enumerate(params):
x = round(a, 9) if x is None else round(x, 9)
y = round(b, 9) if y is None else round(y, 9)
z = round(c, 9) if z is None else round(z, 9)
w = round(d, 9) if w is None else round(w, 9)
x = round(default[0], 9) if x is None else round(x, 9)
y = round(default[1], 9) if y is None else round(y, 9)
z = round(default[2], 9) if z is None else round(z, 9)
w = round(default[3], 9) if w is None else round(w, 9)
result.append((x, y, z, w,))
pbar.update_absolute(idx)
return result,
'''
class ParameterNode(CozyBaseNode):
NAME = "PARAMETER (JOV) ⚙️"
CATEGORY = JOV_CATEGORY
RETURN_TYPES = ()
RETURN_NAMES = ()
SORT = 100
DESCRIPTION = """
"""
@classmethod
def INPUT_TYPES(cls) -> InputType:
d = super().INPUT_TYPES()
d = deep_merge(d, {
"optional": {
"IN": (COZY_TYPE_ANY, {"default": None}),
}
})
return d
def run(self, ident, **kw) -> tuple[Any]:
return kw["IN"],
'''
+2 -2
View File
@@ -65,8 +65,8 @@ app.registerExtension({
const onNodeCreated = nodeType.prototype.onNodeCreated;
nodeType.prototype.onNodeCreated = async function () {
const me = onNodeCreated?.apply(this);
const widget_time = this.widgets.find(w => w.name == 'TIME');
const widget_enable = this.widgets.find(w => w.name == 'ENABLE');
const widget_time = this.widgets.find(w => w.name == 'time');
const widget_enable = this.widgets.find(w => w.name == 'enable');
this.total_timeout = 0;
let showing = false;
let delay_modal;
+1 -1
View File
@@ -27,7 +27,7 @@ app.registerExtension({
nodeType.prototype.onNodeCreated = async function () {
const me = onNodeCreated?.apply(this);
const self = this;
const widget_reset = this.widgets.find(w => w.name == 'RESET');
const widget_reset = this.widgets.find(w => w.name == 'reset');
widget_reset.callback = async() => {
widget_reset.value = false;
apiJovimetrix(self.id, "reset");
+4 -4
View File
@@ -15,10 +15,10 @@ app.registerExtension({
const onNodeCreated = nodeType.prototype.onNodeCreated
nodeType.prototype.onNodeCreated = function () {
const me = onNodeCreated?.apply(this);
const alpha = this.widgets.find(w => w.name == 'ALPHA');
widgetHookControl(this, 'TYPE', alpha, true);
widgetHookValue(this, 'TYPE', 'AA');
widgetHookValue(this, 'TYPE', 'BB');
const alpha = this.widgets.find(w => w.name == 'alpha');
widgetHookControl(this, 'type', alpha, true);
widgetHookValue(this, 'type', 'aa');
widgetHookValue(this, 'type', 'bb');
return me;
}
return nodeType;
+2 -2
View File
@@ -15,8 +15,8 @@ app.registerExtension({
const onNodeCreated = nodeType.prototype.onNodeCreated
nodeType.prototype.onNodeCreated = function () {
const me = onNodeCreated?.apply(this);
widgetHookValue(this, 'TYPE', 'AA');
widgetHookValue(this, 'TYPE', 'BB');
widgetHookValue(this, 'type', 'aa');
widgetHookValue(this, 'type', 'bb');
return me;
}
+1 -1
View File
@@ -16,7 +16,7 @@ app.registerExtension({
const onNodeCreated = nodeType.prototype.onNodeCreated
nodeType.prototype.onNodeCreated = function () {
const me = onNodeCreated?.apply(this);
widgetHookValue(this, 'TYPE', 'AA');
widgetHookValue(this, 'type', 'aa');
return me;
}
/*
+6 -6
View File
@@ -47,10 +47,10 @@ app.registerExtension({
this.widget_report.inputEl.readOnly = true;
this.widget_report.serializeValue = async () => { };
const widget_queue = this.widgets.find(w => w.name == 'Q');
const widget_batch = this.widgets.find(w => w.name == 'BATCH');
const widget_hold = this.widgets.find(w => w.name == 'HOLD');
const widget_reset = this.widgets.find(w => w.name == 'RESET');
const widget_queue = this.widgets.find(w => w.name == 'q');
const widget_batch = this.widgets.find(w => w.name == 'batch');
const widget_hold = this.widgets.find(w => w.name == 'hold');
const widget_reset = this.widgets.find(w => w.name == 'reset');
widget_queue.inputEl.addEventListener('input', function () {
const value = widget_queue.value.split('\n');
@@ -98,7 +98,7 @@ app.registerExtension({
if (outputIndex == 0 && inputType == "COMBO") {
// can link the "same" list -- user breaks it past that, their problem atm.
const widget_queue = this.widgets.find(w => w.name == 'Q');
const widget_queue = this.widgets.find(w => w.name == 'queue');
const widget = inputNode.widgets.find(w => w.name == inputSlot.name);
const values = widget.options.values.join('\n');
if (this.outputs[0].name != _prefix && widget_queue.value != values) {
@@ -129,7 +129,7 @@ app.registerExtension({
this.outputs[0].name = widget.name;
if (widget?.origType == "combo" || widget.type == "COMBO") {
const values = widget.options.values;
const widget_queue = this.widgets.find(w => w.name == 'Q');
const widget_queue = this.widgets.find(w => w.name == 'queue');
// remove all connections that don't match the list?
widget_queue.value = values.join('\n');
update_list(this, values);
+2 -2
View File
@@ -17,13 +17,13 @@ app.registerExtension({
nodeType.prototype.onNodeCreated = async function () {
const me = onNodeCreated?.apply(this);
const self = this;
const widget_reset = this.widgets.find(w => w.name == 'RESET');
const widget_reset = this.widgets.find(w => w.name == 'reset');
widget_reset.callback = async() => {
widget_reset.value = false;
apiJovimetrix(self.id, "reset");
}
self.widget_count = this.widgets.find(w => w.name == 'VAL');
self.widget_count = this.widgets.find(w => w.name == 'value');
async function python_tick(event) {
if (event.detail.id != self.id) {
return;
+2 -2
View File
@@ -21,8 +21,8 @@ app.registerExtension({
this.outputs[3].type = "*";
this.outputs[4].type = "*";
const ab_data = widgetHookValue(this, 'TYPE', 'AA');
widgetHookValue(this, 'TYPE', 'BB');
const ab_data = widgetHookValue(this, 'type', 'aa');
widgetHookValue(this, 'type', 'bb');
const oldCallback = ab_data.callback;
ab_data.callback = () => {