Add post-production nodes with documentation

Implement post-production processing nodes:
- add_film_grain.py: procedural film grain effect
- apply_lut.py: LUT-based color grading
- image_enhancer.py: comprehensive image adjustments (brightness, contrast, gamma, hue, saturation, sharpness, posterize, solarize)
- postproduction.py: all-in-one pipeline (LUT + film grain + upscaling)
- postproduction_advanced.py: extended pipeline with image enhancement controls
- quick_image_upscaler.py: simple tiled AI upscaler

Add markdown documentation for all post-production nodes
This commit is contained in:
TenserTensor
2026-02-13 19:38:03 +03:00
parent f84e17ba0a
commit 22c3d146bd
37 changed files with 912 additions and 20 deletions
+20
View File
@@ -21,6 +21,12 @@ from .nodes.workflow.flux_workfow_settings import TT_FluxWorkflowSettings
from .nodes.workflow.flux_workfow_settings_advanced import TT_FluxWorkflowSettingsAdvanced
from .nodes.workflow.sdxl_workfow_settings import TT_SdxlWorkflowSettings
from .nodes.workflow.sdxl_workfow_settings_advanced import TT_SdxlWorkflowSettingsAdvanced
from .nodes.postproduction.add_film_grain import TT_AddFilmGrain
from .nodes.postproduction.apply_lut import TT_ApplyLut
from .nodes.postproduction.image_enhancer import TT_ImageEnhancer
from .nodes.postproduction.postproduction import TT_Postproduction
from .nodes.postproduction.postproduction_advanced import TT_PostproductionAdvanced
from .nodes.postproduction.quick_image_upscaler import TT_QuickImageUpscaler
NODE_CLASS_MAPPINGS = {
# Context
@@ -36,6 +42,13 @@ NODE_CLASS_MAPPINGS = {
# Loaders
"TT_SdxlModelsLoader": TT_SdxlModelsLoader,
"TT_SdxlModelsLoaderAdvanced": TT_SdxlModelsLoaderAdvanced,
# Postproduction
"TT_ApplyLut": TT_ApplyLut,
"TT_AddFilmGrain": TT_AddFilmGrain,
"TT_QuickImageUpscaler": TT_QuickImageUpscaler,
"TT_ImageEnhancer": TT_ImageEnhancer,
"TT_Postproduction": TT_Postproduction,
"TT_PostproductionAdvanced": TT_PostproductionAdvanced,
# Samplers
"TT_KSampler": TT_KSampler,
"TT_KSamplerAdvanced": TT_KSamplerAdvanced,
@@ -70,6 +83,13 @@ NODE_DISPLAY_NAME_MAPPINGS = {
# Loaders
"TT_SdxlModelsLoader": "TT SDXL Models Loader",
"TT_SdxlModelsLoaderAdvanced": "TT SDXL Models Loader (Advanced)",
# Postproduction
"TT_ApplyLut": "TT Apply LUT",
"TT_AddFilmGrain": "TT Add Film Grain",
"TT_QuickImageUpscaler": "TT Quick Image Upscaler",
"TT_ImageEnhancer": "TT Image Enhancer",
"TT_Postproduction": "TT Postproduction",
"TT_PostproductionAdvanced": "TT Postproduction (Advanced)",
# Samplers
"TT_KSampler": "TT KSampler",
"TT_KSamplerAdvanced": "TT KSampler (Advanced)",
+3
View File
@@ -0,0 +1,3 @@
*
!put_luts_files_here.txt
!.gitignore
View File
+37
View File
@@ -0,0 +1,37 @@
from .postproduction_helpers import apply_film_grain
class TT_AddFilmGrain():
@classmethod
def INPUT_TYPES(cls):
UPSCALE_MODES = ["bilinear", "bicubic", "lanczos", "nearest", "area"]
return {
"required": {
"image": ("IMAGE",),
"seed": ("INT", {"default": 0, "min": 0, "max": 0xffffffffffffffff}),
"scale": ("FLOAT", {"default": 0.25, "min": 0.25, "max": 2.0, "step": 0.05}),
"strength": ("FLOAT", {"default": 0.15, "min": 0.0, "max": 10.0, "step": 0.01}),
"saturation": ("FLOAT", {"default": 0.2, "min": 0.0, "max": 2.0, "step": 0.01}),
"toe": ("FLOAT", {"default": 0.0, "min": -0.2, "max": 0.5, "step": 0.001}),
"upscale_mode": (UPSCALE_MODES, {"advanced": True}),
"antialias": ("BOOLEAN", {"default": False, "label_on": "Enabled", "label_off": "Disabled"}),
}
}
RETURN_TYPES = ("IMAGE",)
RETURN_NAMES = ("IMAGE",)
FUNCTION = "apply_film_grain"
CATEGORY = "TenserTensor/Postproduction"
def apply_film_grain(self, **kwargs):
return (apply_film_grain(
image=kwargs.get("image").clone(),
seed=kwargs.get("seed"),
scale=kwargs.get("scale"),
strength=kwargs.get("strength"),
saturation=kwargs.get("saturation"),
toe=kwargs.get("toe"),
mode=kwargs.get("upscale_mode"),
antialias=kwargs.get("antialias"),
),)
+35
View File
@@ -0,0 +1,35 @@
from .postproduction_helpers import get_lut_files_list, color_correction
class TT_ApplyLut:
LUT_DIR = None
@classmethod
def INPUT_TYPES(cls):
cls.LUT_DIR, LUT_FILES = get_lut_files_list()
COLORSPACES = ["linear", "logarithmic"]
return {
"required": {
"image": ("IMAGE",),
"lut_file": (LUT_FILES, {"advanced": True}),
"strength": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}),
"colorspace": (COLORSPACES, {"advanced": True}),
}
}
RETURN_TYPES = ("IMAGE",)
RETURN_NAMES = ("IMAGE",)
FUNCTION = "apply_lut"
CATEGORY = "TenserTensor/Postproduction"
def apply_lut(self, image, lut_file, strength, colorspace):
return (
color_correction(
image.clone(),
TT_ApplyLut.LUT_DIR,
lut_file,
strength,
colorspace
),
)
+55
View File
@@ -0,0 +1,55 @@
from .postproduction_helpers import enhance_image
class TT_ImageEnhancer():
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"image": ("IMAGE",),
"brightness_factor": ("FLOAT", {"default": 0.0, "min": -1.0, "max": 1.0, "step": 0.01}),
"contrast_factor": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 5.0, "step": 0.01}),
"gamma_factor": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 3.0, "step": 0.01}),
"gamma_gain": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 3.0, "step": 0.01}),
"hue_factor": ("FLOAT", {"default": 0.0, "min": -3.14, "max": 3.14, "step": 0.01}),
"saturation_factor": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 3.0, "step": 0.01}),
"sharpness_factor": ("FLOAT", {"default": 0.0, "min": 0.0, "max": 3.0, "step": 0.01}),
"posterize_bits": ("INT", {"default": 8, "min": 0, "max": 8}),
"solarize_thresholds": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}),
}
}
RETURN_TYPES = ("IMAGE",)
RETURN_NAMES = ("IMAGE",)
FUNCTION = "enhance_image"
CATEGORY = "TenserTensor/Postproduction"
def enhance_image(
self,
image,
brightness_factor,
contrast_factor,
gamma_factor,
gamma_gain,
hue_factor,
saturation_factor,
sharpness_factor,
posterize_bits,
solarize_thresholds
):
timage = image.clone()
timage = enhance_image(
timage,
brightness_factor,
contrast_factor,
gamma_factor,
gamma_gain,
hue_factor,
saturation_factor,
sharpness_factor,
posterize_bits,
solarize_thresholds
)
return (timage,)
+84
View File
@@ -0,0 +1,84 @@
from folder_paths import get_filename_list
from .postproduction_helpers import get_lut_files_list, color_correction, apply_film_grain, upscale_image
class TT_Postproduction():
LUT_DIR = None
@classmethod
def INPUT_TYPES(cls):
cls.LUT_DIR, LUT_FILES = get_lut_files_list()
COLORSPACES = ["linear", "logarithmic"]
UPSCALE_MODES = ["bilinear", "bicubic", "lanczos", "nearest", "area"]
UPSCALE_MODELS = get_filename_list("upscale_models")
DEVICES = ["default", "cpu"]
return {
"required": {
"image": ("IMAGE",),
"apply_lut": ("BOOLEAN", {"default": True, "label_on": "Enabled", "label_off": "Disabled"}),
"lut_file": (LUT_FILES, {"advanced": True}),
"lut_strength": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}),
"lut_colorspace": (COLORSPACES, {"advanced": True}),
"add_film_grain": ("BOOLEAN", {"default": True, "label_on": "Enabled", "label_off": "Disabled"}),
"grain_seed": (
"INT",
{"default": 0, "min": 0, "max": 0xffffffffffffffff, "control_after_generate": True}
),
"grain_scale": ("FLOAT", {"default": 0.25, "min": 0.25, "max": 2.0, "step": 0.05}),
"grain_strength": ("FLOAT", {"default": 0.2, "min": 0.0, "max": 10.0, "step": 0.01}),
"grain_saturation": ("FLOAT", {"default": 0.5, "min": 0.0, "max": 2.0, "step": 0.01}),
"grain_toe": ("FLOAT", {"default": 0.05, "min": -0.2, "max": 0.5, "step": 0.01}),
"grain_upscale_mode": (UPSCALE_MODES, {"advanced": True}),
"grain_antialias": ("BOOLEAN", {"default": True, "label_on": "Enabled", "label_off": "Disabled"}),
"image_upscaler": ("BOOLEAN", {"default": True, "label_on": "Enabled", "label_off": "Disabled"}),
"upscaler_device": (DEVICES, {"advanced": True}),
"upscale_model_name": (UPSCALE_MODELS, {"advanced": True}),
"upscaler_tile": ("INT", {"default": 512, "min": 256, "max": 4096, "step": 64}),
"upscaler_overlap": ("INT", {"default": 64, "min": 0, "max": 256, "step": 8}),
}
}
RETURN_TYPES = ("IMAGE",)
RETURN_NAMES = ("IMAGE",)
FUNCTION = "apply_postprocessing"
CATEGORY = "TenserTensor/Postproduction"
def apply_postprocessing(self, **kwargs):
image = kwargs.get("image").clone()
apply_lut = kwargs.get("apply_lut")
if apply_lut:
image = color_correction(
image=image,
lut_dir=TT_Postproduction.LUT_DIR,
lut_file=kwargs.get("lut_file"),
strength=kwargs.get("lut_strength"),
colorspace=kwargs.get("lut_colorspace")
)
add_film_grain = kwargs.get("add_film_grain")
if add_film_grain:
image = apply_film_grain(
image=image,
seed=kwargs.get("grain_seed"),
scale=kwargs.get("grain_scale"),
strength=kwargs.get("grain_strength"),
saturation=kwargs.get("grain_saturation"),
toe=kwargs.get("grain_toe"),
mode=kwargs.get("grain_upscale_mode"),
antialias=kwargs.get("grain_antialias")
)
image_upscaler = kwargs.get("image_upscaler")
if image_upscaler:
image = upscale_image(
timage=image,
device=kwargs.get("upscaler_device"),
upscale_model_name=kwargs.get("upscale_model_name"),
tile=kwargs.get("upscaler_tile"),
overlap=kwargs.get("upscaler_overlap"),
)
return (image,)
@@ -0,0 +1,109 @@
from folder_paths import get_filename_list
from .postproduction_helpers import get_lut_files_list, color_correction, apply_film_grain, upscale_image, enhance_image
class TT_PostproductionAdvanced():
LUT_DIR = None
@classmethod
def INPUT_TYPES(cls):
cls.LUT_DIR, LUT_FILES = get_lut_files_list()
COLORSPACES = ["linear", "logarithmic"]
UPSCALE_MODES = ["bilinear", "bicubic", "lanczos", "nearest", "area"]
UPSCALE_MODELS = get_filename_list("upscale_models")
DEVICES = ["default", "cpu"]
return {
"required": {
"image": ("IMAGE",),
"image_enhancer": ("BOOLEAN", {"default": True, "label_on": "Enabled", "label_off": "Disabled"}),
"brightness_factor": ("FLOAT", {"default": 0.0, "min": -1.0, "max": 1.0, "step": 0.01}),
"contrast_factor": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 5.0, "step": 0.01}),
"gamma_factor": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 3.0, "step": 0.01}),
"gamma_gain": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 3.0, "step": 0.01}),
"hue_factor": ("FLOAT", {"default": 0.0, "min": -3.14, "max": 3.14, "step": 0.01}),
"saturation_factor": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 3.0, "step": 0.01}),
"sharpness_factor": ("FLOAT", {"default": 0.0, "min": 0.0, "max": 3.0, "step": 0.01}),
"posterize_bits": ("INT", {"default": 8, "min": 0, "max": 8}),
"solarize_thresholds": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}),
"apply_lut": ("BOOLEAN", {"default": True, "label_on": "Enabled", "label_off": "Disabled"}),
"lut_file": (LUT_FILES, {"advanced": True}),
"lut_strength": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}),
"lut_colorspace": (COLORSPACES, {"advanced": True}),
"add_film_grain": ("BOOLEAN", {"default": True, "label_on": "Enabled", "label_off": "Disabled"}),
"grain_seed": (
"INT",
{"default": 0, "min": 0, "max": 0xffffffffffffffff, "control_after_generate": True}
),
"grain_scale": ("FLOAT", {"default": 0.25, "min": 0.25, "max": 2.0, "step": 0.05}),
"grain_strength": ("FLOAT", {"default": 0.2, "min": 0.0, "max": 10.0, "step": 0.01}),
"grain_saturation": ("FLOAT", {"default": 0.5, "min": 0.0, "max": 2.0, "step": 0.01}),
"grain_toe": ("FLOAT", {"default": 0.05, "min": -0.2, "max": 0.5, "step": 0.01}),
"grain_upscale_mode": (UPSCALE_MODES, {"advanced": True}),
"grain_antialias": ("BOOLEAN", {"default": True, "label_on": "Enabled", "label_off": "Disabled"}),
"image_upscaler": ("BOOLEAN", {"default": True, "label_on": "Enabled", "label_off": "Disabled"}),
"upscaler_device": (DEVICES, {"advanced": True}),
"upscale_model_name": (UPSCALE_MODELS, {"advanced": True}),
"upscaler_tile": ("INT", {"default": 512, "min": 256, "max": 4096, "step": 64}),
"upscaler_overlap": ("INT", {"default": 64, "min": 0, "max": 256, "step": 8}),
}
}
RETURN_TYPES = ("IMAGE",)
RETURN_NAMES = ("IMAGE",)
FUNCTION = "apply_postprocessing"
CATEGORY = "TenserTensor/Postproduction"
def apply_postprocessing(self, **kwargs):
image = kwargs.get("image").clone()
image_enhancer = kwargs.get("image_enhancer")
if image_enhancer:
image = enhance_image(
timage=image,
brightness_factor=kwargs.get("brightness_factor"),
contrast_factor=kwargs.get("contrast_factor"),
gamma_factor=kwargs.get("gamma_factor"),
gamma_gain=kwargs.get("gamma_gain"),
hue_factor=kwargs.get("hue_factor"),
saturation_factor=kwargs.get("saturation_factor"),
sharpness_factor=kwargs.get("sharpness_factor"),
posterize_bits=kwargs.get("posterize_bits"),
solarize_thresholds=kwargs.get("solarize_thresholds")
)
apply_lut = kwargs.get("apply_lut")
if apply_lut:
image = color_correction(
image=image,
lut_dir=TT_PostproductionAdvanced.LUT_DIR,
lut_file=kwargs.get("lut_file"),
strength=kwargs.get("lut_strength"),
colorspace=kwargs.get("lut_colorspace")
)
add_film_grain = kwargs.get("add_film_grain")
if add_film_grain:
image = apply_film_grain(
image=image,
seed=kwargs.get("grain_seed"),
scale=kwargs.get("grain_scale"),
strength=kwargs.get("grain_strength"),
saturation=kwargs.get("grain_saturation"),
toe=kwargs.get("grain_toe"),
mode=kwargs.get("grain_upscale_mode"),
antialias=kwargs.get("grain_antialias")
)
image_upscaler = kwargs.get("image_upscaler")
if image_upscaler:
image = upscale_image(
timage=image,
device=kwargs.get("upscaler_device"),
upscale_model_name=kwargs.get("upscale_model_name"),
tile=kwargs.get("upscaler_tile"),
overlap=kwargs.get("upscaler_overlap"),
)
return (image,)
@@ -0,0 +1,235 @@
from pathlib import Path
import colour
import comfy.utils as U
import kornia
import torch
import torch.nn.functional as F
from comfy import model_management
from folder_paths import get_folder_paths, get_filename_list, get_full_path_or_raise
from spandrel import ModelLoader, ImageModelDescriptor
def get_lut_files_list():
base = get_folder_paths("custom_nodes")[0]
lut_dir = Path(base) / "ComfyUI-TenserTensor" / "lut"
if not lut_dir.is_dir():
raise FileNotFoundError(f"lut dir not found: {lut_dir}")
files = [file.name for file in lut_dir.glob("*.cube")]
return lut_dir, sorted(files)
def color_correction(image, lut_dir, lut_file, strength, colorspace):
is_log = colorspace == "logarithmic"
device, dtype = image.device, image.dtype
image = image.detach().cpu().numpy()
retval = image.copy()
if is_log:
retval **= 1 / 2.2
retval = colour.read_LUT(str(lut_dir / lut_file)).apply(retval)
if is_log:
retval **= 2.2
if strength < 1.0:
retval = strength * retval + (1 - strength) * image
return torch.from_numpy(retval).to(device, dtype)
def apply_film_grain(image, seed, scale, strength, saturation, toe, mode, antialias):
batch, height, width, channels = image.shape
image = image.detach()
if seed is not None:
torch.manual_seed(seed)
grain = torch.rand(batch, int(height // scale), int(width // scale), 3)
ycbcr = kornia.color.rgb_to_ycbcr(grain.movedim(-1, 1)).movedim(1, -1)
for idx, ksize in enumerate([3, 15, 11]):
sigma = (ksize / 3.0,) * 2
kernel_size = (ksize,) * 2
channel = ycbcr[..., idx:idx + 1].movedim(-1, 1)
ycbcr[..., idx] = kornia.filters.gaussian_blur2d(
channel,
kernel_size=kernel_size,
sigma=sigma,
border_type='reflect'
).movedim(1, -1).squeeze(-1)
grain = (kornia.color.ycbcr_to_rgb(ycbcr.movedim(-1, 1)).movedim(1, -1) - 0.5) * strength
grain[..., 0] *= 2
grain[..., 2] *= 3
grain += 1
mono = grain[..., 1:2].expand(-1, -1, -1, 3)
grain = grain * saturation + mono * (1 - saturation)
grain = F.interpolate(
grain.movedim(-1, 1),
size=(height, width),
mode=mode,
antialias=antialias if mode in ['bilinear', 'bicubic'] else False
).movedim(1, -1)
base = image[..., :3]
shadow_lift = 1 - toe
image[..., :3] = torch.clip(
(1 - (1 - base) * grain) * shadow_lift + toe,
0.0, 1.0
)
return image
def _load_upscale_model(upscale_model_name):
model_path = get_full_path_or_raise("upscale_models", upscale_model_name)
try:
state_dict = U.load_torch_file(model_path, safe_load=True)
except Exception as e:
raise RuntimeError(f"Failed to load model file {model_path}: {e}")
state_dict = U.state_dict_prefix_replace(state_dict, {"module.": ""})
upscale_model = ModelLoader().load_from_state_dict(state_dict).eval()
if not isinstance(upscale_model, ImageModelDescriptor):
raise TypeError(f"Expected ImageModelDescriptor, got {type(upscale_model).__name__}")
return upscale_model
def upscale_image(timage, device, upscale_model_name, tile, overlap):
upscale_device = model_management.get_torch_device() if device == "default" else torch.device("cpu")
upscale_model = _load_upscale_model(upscale_model_name)
iimage = timage.movedim(-1, 1).to(upscale_device)
batch, channels, height, width = iimage.shape
print(f"iimage.shape: {iimage.shape}")
BUFFER_FACTOR = 384.0
model_mem = model_management.module_size(upscale_model.model)
tile_mem = (tile * tile * 3) * iimage.element_size() * max(upscale_model.scale, 1) * BUFFER_FACTOR
total_mem = model_mem + tile_mem + iimage.nelement() * iimage.element_size()
model_management.free_memory(total_mem, upscale_device)
upscale_model.to(upscale_device)
try:
while True:
try:
steps = batch * U.get_tiled_scale_steps(
width,
height,
tile_x=tile,
tile_y=tile,
overlap=overlap
)
pbar = U.ProgressBar(steps)
simage = U.tiled_scale(
iimage,
upscale_model,
tile_x=tile,
tile_y=tile,
overlap=overlap,
upscale_amount=upscale_model.scale,
pbar=pbar
)
break
except model_management.OOM_EXCEPTION as e:
pbar = None
tile //= 2
if tile < 128:
raise e
finally:
if upscale_device.type != "cpu":
upscale_model.to("cpu")
return torch.clamp(simage.movedim(1, -1), min=0.0, max=1.0)
def adjust_brightness(image, factor, clip_output=True):
timage = image.movedim(-1, 1)
return kornia.enhance.adjust_brightness(timage, factor, clip_output).movedim(1, -1)
def adjust_contrast(image, factor, clip_output=True):
timage = image.movedim(-1, 1)
return kornia.enhance.adjust_contrast(timage, factor, clip_output).movedim(1, -1)
def adjust_gamma(image, gamma, gain=1.0):
timage = image.movedim(-1, 1)
return kornia.enhance.adjust_gamma(timage, gamma, gain).movedim(1, -1)
def adjust_hue(image, factor):
timage = image.movedim(-1, 1)
return kornia.enhance.adjust_hue(timage, factor).movedim(1, -1)
def adjust_saturation(image, factor):
timage = image.movedim(-1, 1)
return kornia.enhance.adjust_saturation(timage, factor).movedim(1, -1)
def sharpness(image, factor):
timage = image.movedim(-1, 1)
return kornia.enhance.sharpness(timage, factor).movedim(1, -1)
def posterize(image, bits):
timage = image.movedim(-1, 1)
return kornia.enhance.posterize(timage, bits).movedim(1, -1)
def solarize(image, thresholds=0.5, additions=None):
timage = image.movedim(-1, 1)
return kornia.enhance.solarize(timage, thresholds, additions).movedim(1, -1)
def enhance_image(
timage,
brightness_factor,
contrast_factor,
gamma_factor,
gamma_gain,
hue_factor,
saturation_factor,
sharpness_factor,
posterize_bits,
solarize_thresholds
):
if brightness_factor != 0.0:
timage = adjust_brightness(timage, brightness_factor)
if contrast_factor != 1.0:
timage = adjust_contrast(timage, contrast_factor)
if gamma_factor != 1.0:
timage = adjust_gamma(timage, gamma_factor, gamma_gain)
if hue_factor != 0.0:
timage = adjust_hue(timage, hue_factor)
if saturation_factor != 1.0:
timage = adjust_saturation(timage, saturation_factor)
if sharpness_factor != 0.0:
timage = sharpness(timage, sharpness_factor)
if posterize_bits != 8:
timage = posterize(timage, posterize_bits)
if solarize_thresholds != 1.0:
timage = solarize(timage, solarize_thresholds)
return timage
@@ -0,0 +1,37 @@
from folder_paths import get_filename_list
from .postproduction_helpers import upscale_image
class TT_QuickImageUpscaler():
@classmethod
def INPUT_TYPES(cls):
DEVICES = ["default", "cpu"]
UPSCALE_MODELS = get_filename_list("upscale_models")
return {
"required": {
"image": ("IMAGE",),
"device": (DEVICES, {"advanced": True}),
"upscale_model_name": (UPSCALE_MODELS, {"advanced": True}),
"tile": ("INT", {"default": 512, "min": 256, "max": 4096, "step": 64}),
"overlap": ("INT", {"default": 64, "min": 0, "max": 256, "step": 8}),
}
}
RETURN_TYPES = ("IMAGE",)
RETURN_NAMES = ("IMAGE",)
FUNCTION = "upscale_image"
CATEGORY = "TenserTensor/Postproduction"
def upscale_image(self, image, device, upscale_model_name, tile, overlap):
timage = image.clone()
return (upscale_image(
timage=timage,
device=device,
upscale_model_name=upscale_model_name,
tile=tile,
overlap=overlap,
),)
+34
View File
@@ -0,0 +1,34 @@
## TT Add Film Grain *TT_AddFilmGrain*
*This description was generated with AI assistance. If you spot any errors, please create an issue on GitHub.*
Add procedural film grain texture to images for a cinematic look.
### Inputs
| Parameter | Type | Required | Description |
|----------------|---------|----------|---------------------------------------------------------------------------------|
| `image` | IMAGE | Yes | Input image to add grain to |
| `seed` | INT | Yes | Random seed for grain pattern (0 to 2^64-1, default: 0) |
| `scale` | FLOAT | Yes | Scale of grain texture (0.25-2.0, default: 0.25) |
| `strength` | FLOAT | Yes | Intensity of grain effect (0.0-10.0, default: 0.15) |
| `saturation` | FLOAT | Yes | Color saturation of grain (0.0-2.0, default: 0.2) |
| `toe` | FLOAT | Yes | Toe adjustment for grain distribution (-0.2 to 0.5, default: 0.0) |
| `upscale_mode` | STRING | Yes | Interpolation mode for grain (bilinear/bicubic/lanczos/nearest/area) - advanced |
| `antialias` | BOOLEAN | Yes | Enable antialiasing for grain (default: False) |
### Outputs
| Parameter | Type | Description |
|-----------|-------|-------------------------------|
| `IMAGE` | IMAGE | Image with applied film grain |
### Usage
Add realistic film grain texture to images for a cinematic aesthetic. Adjust scale for grain size, strength for
intensity, and saturation for color. The toe parameter controls the distribution curve of grain in shadows/highlights.
Use different seeds for varied grain patterns.
---
[View on GitHub](https://github.com/tenser-tensor/ComfyUI-TenserTensor)
+30
View File
@@ -0,0 +1,30 @@
## TT Apply LUT *TT_ApplyLut*
*This description was generated with AI assistance. If you spot any errors, please create an issue on GitHub.*
Apply color grading LUT (Look-Up Table) to images for professional color correction.
### Inputs
| Parameter | Type | Required | Description |
|--------------|----------|----------|----------------------------------------------------------------|
| `image` | IMAGE | Yes | Input image to apply LUT to |
| `lut_file` | LUT_FILE | Yes | LUT file to apply (from LUT directory) - advanced |
| `strength` | FLOAT | Yes | Blend strength of LUT effect (0.0-1.0, default: 1.0) |
| `colorspace` | STRING | Yes | Colorspace for LUT application (linear/logarithmic) - advanced |
### Outputs
| Parameter | Type | Description |
|-----------|-------|--------------------------------------|
| `IMAGE` | IMAGE | Image with applied LUT color grading |
### Usage
Apply professional color grading using LUT files. Place your .cube LUT files in the designated LUT directory. Adjust
strength to blend between original and graded image (1.0 = full LUT, 0.0 = original). Choose colorspace based on your
LUT file's intended working space.
---
[View on GitHub](https://github.com/tenser-tensor/ComfyUI-TenserTensor)
+1 -1
View File
@@ -1,4 +1,4 @@
## TT Base Context (TT_BaseContext)
## TT Base Context *TT_BaseContext*
*This description was generated with AI assistance. If you spot any errors, please create an issue on GitHub.*
+1 -1
View File
@@ -1,4 +1,4 @@
## TT_ClipTextEncodeFlux
## TT CLIP Text Encode FLUX *TT_ClipTextEncodeFlux*
*This description was generated with AI assistance. If you spot any errors, please create an issue on GitHub.*
+1 -1
View File
@@ -1,4 +1,4 @@
## TT_ClipTextEncodeFluxContext
## TT CLIP Text Encode FLUX (Context) *TT_ClipTextEncodeFluxContext*
*This description was generated with AI assistance. If you spot any errors, please create an issue on GitHub.*
+1 -1
View File
@@ -1,4 +1,4 @@
## TT_ClipTextEncodeSdxl
## TT CLIP Text Encode SDXL *TT_ClipTextEncodeSdxl*
*This description was generated with AI assistance. If you spot any errors, please create an issue on GitHub.*
+1 -1
View File
@@ -1,4 +1,4 @@
## TT_ClipTextEncodeSdxlContext
## TT CLIP Text Encode SDXL (Context) *TT_ClipTextEncodeSdxlContext*
*This description was generated with AI assistance. If you spot any errors, please create an issue on GitHub.*
+1 -1
View File
@@ -1,4 +1,4 @@
## TT Context (TT_Context)
## TT Context *TT_Context*
*This description was generated with AI assistance. If you spot any errors, please create an issue on GitHub.*
+1 -1
View File
@@ -1,4 +1,4 @@
## TT Context Passthrough (TT_ContextPassthrough)
## TT Context Passthrough *TT_ContextPassthrough*
*This description was generated with AI assistance. If you spot any errors, please create an issue on GitHub.*
+1 -1
View File
@@ -1,4 +1,4 @@
## TT Even Larger Context (TT_EvenLargerContext)
## TT Even Larger Context *TT_EvenLargerContext*
*This description was generated with AI assistance. If you spot any errors, please create an issue on GitHub.*
+1 -1
View File
@@ -1,4 +1,4 @@
# TT_FluxWorkflowSettings
# TT FLUX Workflow Settings *TT_FluxWorkflowSettings*
*This description was generated with AI assistance. If you spot any errors, please create an issue on GitHub.*
+1 -1
View File
@@ -1,4 +1,4 @@
# TT_FluxWorkflowSettingsAdvanced
# TT FLUX Workflow Settings (Advanced) *TT_FluxWorkflowSettingsAdvanced*
*This description was generated with AI assistance. If you spot any errors, please create an issue on GitHub.*
+36
View File
@@ -0,0 +1,36 @@
## TT Image Enhancer *TT_ImageEnhancer*
*This description was generated with AI assistance. If you spot any errors, please create an issue on GitHub.*
Comprehensive image adjustment node with multiple enhancement controls.
### Inputs
| Parameter | Type | Required | Description |
|-----------------------|-------|----------|--------------------------------------------------------------------------|
| `image` | IMAGE | Yes | Input image to enhance |
| `brightness_factor` | FLOAT | Yes | Brightness adjustment (-1.0 to 1.0, default: 0.0, 0.0=no effect) |
| `contrast_factor` | FLOAT | Yes | Contrast multiplier (0.0-5.0, default: 1.0, 1.0=no effect) |
| `gamma_factor` | FLOAT | Yes | Gamma correction value (0.0-3.0, default: 1.0, 1.0=no effect) |
| `gamma_gain` | FLOAT | Yes | Gamma gain multiplier (0.0-3.0, default: 1.0, 1.0=no effect) |
| `hue_factor` | FLOAT | Yes | Hue rotation in radians (-π to π, default: 0.0, 0.0=no effect) |
| `saturation_factor` | FLOAT | Yes | Saturation multiplier (0.0-3.0, default: 1.0, 1.0=no effect) |
| `sharpness_factor` | FLOAT | Yes | Sharpness amount (0.0-3.0, default: 0.0, 0.0=no effect) |
| `posterize_bits` | INT | Yes | Bit depth for posterization (0-8, default: 8, 8=no effect) |
| `solarize_thresholds` | FLOAT | Yes | Threshold for solarization effect (0.0-1.0, default: 1.0, 1.0=no effect) |
### Outputs
| Parameter | Type | Description |
|-----------|-------|-----------------------------------------|
| `IMAGE` | IMAGE | Enhanced image with applied adjustments |
### Usage
All-in-one image enhancement node for adjusting brightness, contrast, colors, and applying effects. Use default values (
brightness: 0.0, contrast/gamma/saturation: 1.0, posterize: 8, solarize: 1.0) for no effect. Adjust individual
parameters as needed - effects are applied sequentially.
---
[View on GitHub](https://github.com/tenser-tensor/ComfyUI-TenserTensor)
+1 -1
View File
@@ -1,4 +1,4 @@
## TT_KSampler
## TT KSampler *TT_KSampler*
*This description was generated with AI assistance. If you spot any errors, please create an issue on GitHub.*
+1 -1
View File
@@ -1,4 +1,4 @@
## TT_KSamplerAdvanced
## TT KSampler (Advanced) *TT_KSamplerAdvanced*
*This description was generated with AI assistance. If you spot any errors, please create an issue on GitHub.*
+1 -1
View File
@@ -1,4 +1,4 @@
## TT_KSamplerContext
## TT KSampler (Context) *TT_KSamplerContext*
Context-based sampler that extracts parameters from workflow context.
+1 -1
View File
@@ -1,4 +1,4 @@
## TT_KSamplerTwoStage
## TT KSampler (Two Stages) *TT_KSamplerTwoStage*
Two-stage sampler with separate draft and refinement passes.
+1 -1
View File
@@ -1,4 +1,4 @@
## TT FLUX Large Context (TT_LargeContextFlux)
## TT FLUX Large Context *TT_LargeContextFlux*
*This description was generated with AI assistance. If you spot any errors, please create an issue on GitHub.*
+1 -1
View File
@@ -1,4 +1,4 @@
## TT SDXL Large Context (TT_LargeContextSdxl)
## TT SDXL Large Context *TT_LargeContextSdxl*
*This description was generated with AI assistance. If you spot any errors, please create an issue on GitHub.*
+1 -1
View File
@@ -1,4 +1,4 @@
# TT Latent Factory
# TT Latent Factory *TT_LatentFactory*
*This description was generated with AI assistance. If you spot any errors, please create an issue on GitHub.*
+44
View File
@@ -0,0 +1,44 @@
## TT Postproduction *TT_Postproduction*
*This description was generated with AI assistance. If you spot any errors, please create an issue on GitHub.*
All-in-one post-production node combining LUT color grading, film grain, and upscaling.
### Inputs
| Parameter | Type | Required | Description |
|----------------------|---------------|----------|------------------------------------------------------------|
| `image` | IMAGE | Yes | Input image to process |
| `apply_lut` | BOOLEAN | Yes | Enable LUT color grading (default: True) |
| `lut_file` | LUT_FILE | Yes | LUT file to apply - advanced |
| `lut_strength` | FLOAT | Yes | LUT blend strength (0.0-1.0, default: 1.0) |
| `lut_colorspace` | STRING | Yes | Colorspace for LUT (linear/logarithmic) - advanced |
| `add_film_grain` | BOOLEAN | Yes | Enable film grain effect (default: True) |
| `grain_seed` | INT | Yes | Seed for grain pattern (0 to 2^64-1, default: 0) |
| `grain_scale` | FLOAT | Yes | Grain texture scale (0.25-2.0, default: 0.25) |
| `grain_strength` | FLOAT | Yes | Grain intensity (0.0-10.0, default: 0.2) |
| `grain_saturation` | FLOAT | Yes | Grain color saturation (0.0-2.0, default: 0.5) |
| `grain_toe` | FLOAT | Yes | Grain distribution toe (-0.2 to 0.5, default: 0.05) |
| `grain_upscale_mode` | STRING | Yes | Grain interpolation mode - advanced |
| `grain_antialias` | BOOLEAN | Yes | Grain antialiasing (default: True) |
| `image_upscaler` | BOOLEAN | Yes | Enable image upscaling (default: True) |
| `upscaler_device` | STRING | Yes | Device for upscaler (default/cpu) - advanced |
| `upscale_model_name` | UPSCALE_MODEL | Yes | Upscale model to use - advanced |
| `upscaler_tile` | INT | Yes | Tile size for upscaling (256-4096, step: 64, default: 512) |
| `upscaler_overlap` | INT | Yes | Tile overlap (0-256, step: 8, default: 64) |
### Outputs
| Parameter | Type | Description |
|-----------|-------|--------------------------------------|
| `IMAGE` | IMAGE | Processed image with applied effects |
### Usage
Complete post-production pipeline in one node. Toggle each effect on/off with boolean switches. Processing order: LUT →
Film Grain → Upscale. Disable any effect by setting its toggle to False. All effects are optional and can be used
independently or combined.
---
[View on GitHub](https://github.com/tenser-tensor/ComfyUI-TenserTensor)
+50
View File
@@ -0,0 +1,50 @@
## TT Postproduction (Advanced) *TT_PostproductionAdvanced*
Extended post-production node with image enhancement, LUT color grading, film grain, and upscaling.
### Inputs
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `image` | IMAGE | Yes | Input image to process |
| `image_enhancer` | BOOLEAN | Yes | Enable image enhancement (default: True) |
| `brightness_factor` | FLOAT | Yes | Brightness adjustment (-1.0 to 1.0, default: 0.0) |
| `contrast_factor` | FLOAT | Yes | Contrast multiplier (0.0-5.0, default: 1.0) |
| `gamma_factor` | FLOAT | Yes | Gamma correction (0.0-3.0, default: 1.0) |
| `gamma_gain` | FLOAT | Yes | Gamma gain (0.0-3.0, default: 1.0) |
| `hue_factor` | FLOAT | Yes | Hue rotation (-π to π, default: 0.0) |
| `saturation_factor` | FLOAT | Yes | Saturation multiplier (0.0-3.0, default: 1.0) |
| `sharpness_factor` | FLOAT | Yes | Sharpness amount (0.0-3.0, default: 0.0) |
| `posterize_bits` | INT | Yes | Posterization bit depth (0-8, default: 8) |
| `solarize_thresholds` | FLOAT | Yes | Solarization threshold (0.0-1.0, default: 1.0) |
| `apply_lut` | BOOLEAN | Yes | Enable LUT color grading (default: True) |
| `lut_file` | LUT_FILE | Yes | LUT file to apply - advanced |
| `lut_strength` | FLOAT | Yes | LUT blend strength (0.0-1.0, default: 1.0) |
| `lut_colorspace` | STRING | Yes | Colorspace for LUT (linear/logarithmic) - advanced |
| `add_film_grain` | BOOLEAN | Yes | Enable film grain effect (default: True) |
| `grain_seed` | INT | Yes | Seed for grain pattern (0 to 2^64-1, default: 0) |
| `grain_scale` | FLOAT | Yes | Grain texture scale (0.25-2.0, default: 0.25) |
| `grain_strength` | FLOAT | Yes | Grain intensity (0.0-10.0, default: 0.2) |
| `grain_saturation` | FLOAT | Yes | Grain color saturation (0.0-2.0, default: 0.5) |
| `grain_toe` | FLOAT | Yes | Grain distribution toe (-0.2 to 0.5, default: 0.05) |
| `grain_upscale_mode` | STRING | Yes | Grain interpolation mode - advanced |
| `grain_antialias` | BOOLEAN | Yes | Grain antialiasing (default: True) |
| `image_upscaler` | BOOLEAN | Yes | Enable image upscaling (default: True) |
| `upscaler_device` | STRING | Yes | Device for upscaler (default/cpu) - advanced |
| `upscale_model_name` | UPSCALE_MODEL | Yes | Upscale model to use - advanced |
| `upscaler_tile` | INT | Yes | Tile size for upscaling (256-4096, step: 64, default: 512) |
| `upscaler_overlap` | INT | Yes | Tile overlap (0-256, step: 8, default: 64) |
### Outputs
| Parameter | Type | Description |
|-----------|------|-------------|
| IMAGE | IMAGE | Processed image with applied effects |
### Usage
Complete post-production pipeline with full enhancement controls. Processing order: Image Enhancement → LUT → Film Grain → Upscale. Toggle each effect on/off independently. Image enhancement includes brightness, contrast, gamma, hue, saturation, sharpness, posterize, and solarize adjustments. All effects are optional.
---
[View on GitHub](https://github.com/tenser-tensor/ComfyUI-TenserTensor)
+29
View File
@@ -0,0 +1,29 @@
## TT Quick Image Upscaler *TT_QuickImageUpscaler*
*This description was generated with AI assistance. If you spot any errors, please create an issue on GitHub.*
Tiled image upscaler using AI upscale models.
### Inputs
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| image | IMAGE | Yes | Input image to upscale |
| device | STRING | Yes | Device for upscaling (default/cpu) - advanced |
| upscale_model_name | UPSCALE_MODEL | Yes | Upscale model to use - advanced |
| tile | INT | Yes | Tile size for processing (256-4096, step: 64, default: 512) |
| overlap | INT | Yes | Tile overlap to reduce seams (0-256, step: 8, default: 64) |
### Outputs
| Parameter | Type | Description |
|-----------|------|-------------|
| IMAGE | IMAGE | Upscaled image |
### Usage
Quick and simple AI upscaling node using tiled processing for memory efficiency. Select an upscale model from your upscale_models directory. Adjust tile size based on VRAM - smaller tiles use less memory. Increase overlap to reduce visible seams between tiles.
---
[View on GitHub](https://github.com/tenser-tensor/ComfyUI-TenserTensor)
+1 -1
View File
@@ -1,4 +1,4 @@
## TT_SdxlModelsLoader
## TT SDXL Models Loader *TT_SdxlModelsLoader*
*This description was generated with AI assistance. If you spot any errors, please create an issue on GitHub.*
+1 -1
View File
@@ -1,4 +1,4 @@
## TT_SdxlModelsLoaderAdvanced
## TT SDXL Models Loader (Advanced) *TT_SdxlModelsLoaderAdvanced*
*This description was generated with AI assistance. If you spot any errors, please create an issue on GitHub.*
+1 -1
View File
@@ -1,4 +1,4 @@
# TT_SdxlWorkflowSettings
# TT SDXL Workflow Settings *TT_SdxlWorkflowSettings*
*This description was generated with AI assistance. If you spot any errors, please create an issue on GitHub.*
@@ -0,0 +1,54 @@
## TT SDXL Workflow Settings (Advanced) *TT_SdxlWorkflowSettingsAdvanced*
Advanced SDXL workflow configuration with separate CLIP-L/G prompts and aesthetic scores.
### Inputs
| Parameter | Type | Required | Description |
|-------------------|-----------|----------|---------------------------------------------------------|
| `seed` | INT | Yes | Random seed (0 to 2^64-1, default: 0) |
| `steps` | INT | Yes | Sampling steps (1-10000, default: 30) |
| `cfg` | FLOAT | Yes | CFG scale (0.0-100.0, default: 7.0) |
| `sampler_name` | SAMPLER | Yes | Sampler algorithm |
| `scheduler` | SCHEDULER | Yes | Noise scheduler |
| `clip_l_positive` | STRING | Yes | CLIP-L positive prompt (multiline) |
| `clip_g_positive` | STRING | Yes | CLIP-G positive prompt (multiline) |
| `clip_l_negative` | STRING | Yes | CLIP-L negative prompt (multiline) |
| `clip_g_negative` | STRING | Yes | CLIP-G negative prompt (multiline) |
| `ascore_positive` | FLOAT | Yes | Aesthetic score for positive (0.0-1000.0, default: 9.0) |
| `ascore_negative` | FLOAT | Yes | Aesthetic score for negative (0.0-1000.0, default: 6.0) |
| `width` | INT | Yes | Image width (default: 512) |
| `height` | INT | Yes | Image height (default: 512) |
| `target_width` | INT | Yes | Target width for conditioning (default: 512) |
| `target_height` | INT | Yes | Target height for conditioning (default: 512) |
### Outputs
| Parameter | Type | Description |
|-------------------|--------------------|--------------------------------------------|
| `WORKFLOW_CONFIG` | TT_WORKFLOW_CONFIG | Complete workflow configuration dictionary |
| `SEED` | INT | Random seed |
| `STEPS` | INT | Sampling steps |
| `CFG` | FLOAT | CFG scale |
| `SAMPLER_NAME` | STRING | Sampler name |
| `SCHEDULER` | STRING | Scheduler name |
| `CLIP_L_POSITIVE` | STRING | CLIP-L positive prompt |
| `CLIP_G_POSITIVE` | STRING | CLIP-G positive prompt |
| `CLIP_L_NEGATIVE` | STRING | CLIP-L negative prompt |
| `CLIP_G_NEGATIVE` | STRING | CLIP-G negative prompt |
| `ASCORE_POSITIVE` | FLOAT | Aesthetic score positive |
| `ASCORE_NEGATIVE` | FLOAT | Aesthetic score negative |
| `WIDTH` | INT | Width |
| `HEIGHT` | INT | Height |
| `TARGET_WIDTH` | INT | Target width |
| `TARGET_HEIGHT` | INT | Target height |
### Usage
Configure all SDXL workflow parameters with fine-grained control over CLIP-L and CLIP-G prompts separately, plus
aesthetic scores and target dimensions. Returns both a bundled config dictionary and individual parameters for flexible
workflow design.
---
[View on GitHub](https://github.com/tenser-tensor/ComfyUI-TenserTensor)