wip add AI generated descriptions to all nodes

This commit is contained in:
pythongosssss
2026-02-16 14:02:17 -08:00
parent 88e6370527
commit ecec1310b2
119 changed files with 1059 additions and 15 deletions

116
nodes.py
View File

@@ -70,6 +70,7 @@ class CLIPTextEncode(ComfyNodeABC):
CATEGORY = "conditioning"
DESCRIPTION = "Encodes a text prompt using a CLIP model into an embedding that can be used to guide the diffusion model towards generating specific images."
SHORT_DESCRIPTION = "Encodes text prompts using CLIP for guiding diffusion models."
SEARCH_ALIASES = ["text", "prompt", "text prompt", "positive prompt", "negative prompt", "encode text", "text encoder", "encode prompt"]
def encode(self, clip, text):
@@ -87,6 +88,8 @@ class ConditioningCombine:
FUNCTION = "combine"
CATEGORY = "conditioning"
DESCRIPTION = "Combines two conditioning inputs into one by appending them together."
SHORT_DESCRIPTION = None
SEARCH_ALIASES = ["combine", "merge conditioning", "combine prompts", "merge prompts", "mix prompts", "add prompt"]
def combine(self, conditioning_1, conditioning_2):
@@ -104,6 +107,8 @@ class ConditioningAverage :
FUNCTION = "addWeighted"
CATEGORY = "conditioning"
DESCRIPTION = "Blends two conditioning inputs using a weighted average, allowing smooth interpolation between prompts based on a strength parameter."
SHORT_DESCRIPTION = "Blends two conditionings via weighted average interpolation."
def addWeighted(self, conditioning_to, conditioning_from, conditioning_to_strength):
out = []
@@ -143,6 +148,8 @@ class ConditioningConcat:
FUNCTION = "concat"
CATEGORY = "conditioning"
DESCRIPTION = "Concatenates conditioning tokens from one conditioning onto another, extending the token sequence to combine their effects."
SHORT_DESCRIPTION = "Concatenates conditioning tokens to combine prompt effects."
def concat(self, conditioning_to, conditioning_from):
out = []
@@ -176,6 +183,8 @@ class ConditioningSetArea:
FUNCTION = "append"
CATEGORY = "conditioning"
DESCRIPTION = "Sets a rectangular area on conditioning using pixel coordinates, allowing the prompt to apply only to a specific region of the image."
SHORT_DESCRIPTION = "Restricts conditioning to a specific pixel-coordinate area."
def append(self, conditioning, width, height, x, y, strength):
c = node_helpers.conditioning_set_values(conditioning, {"area": (height // 8, width // 8, y // 8, x // 8),
@@ -197,6 +206,8 @@ class ConditioningSetAreaPercentage:
FUNCTION = "append"
CATEGORY = "conditioning"
DESCRIPTION = "Sets a rectangular area on conditioning using percentage-based coordinates, allowing the prompt to apply to a proportional region of the image."
SHORT_DESCRIPTION = "Restricts conditioning to a percentage-based area."
def append(self, conditioning, width, height, x, y, strength):
c = node_helpers.conditioning_set_values(conditioning, {"area": ("percentage", height, width, y, x),
@@ -214,6 +225,8 @@ class ConditioningSetAreaStrength:
FUNCTION = "append"
CATEGORY = "conditioning"
DESCRIPTION = "Sets the strength of a conditioning area."
SHORT_DESCRIPTION = None
def append(self, conditioning, strength):
c = node_helpers.conditioning_set_values(conditioning, {"strength": strength})
@@ -234,6 +247,8 @@ class ConditioningSetMask:
FUNCTION = "append"
CATEGORY = "conditioning"
DESCRIPTION = "Applies a mask to conditioning so the prompt only affects the masked region, with adjustable strength and optional bounds-based area restriction."
SHORT_DESCRIPTION = "Applies a mask to limit conditioning to a region."
def append(self, conditioning, mask, set_cond_area, strength):
set_area_to_bounds = False
@@ -257,6 +272,8 @@ class ConditioningZeroOut:
FUNCTION = "zero_out"
CATEGORY = "advanced/conditioning"
DESCRIPTION = "Zeros out all conditioning tensors including pooled output, producing an empty unconditional embedding."
SHORT_DESCRIPTION = "Zeros out conditioning to produce an empty embedding."
def zero_out(self, conditioning):
c = []
@@ -283,6 +300,8 @@ class ConditioningSetTimestepRange:
FUNCTION = "set_range"
CATEGORY = "advanced/conditioning"
DESCRIPTION = "Sets the start and end timestep percentages for conditioning, controlling which portion of the sampling process it is active during."
SHORT_DESCRIPTION = "Limits conditioning to a specific timestep range."
def set_range(self, conditioning, start, end):
c = node_helpers.conditioning_set_values(conditioning, {"start_percent": start,
@@ -304,6 +323,7 @@ class VAEDecode:
CATEGORY = "latent"
DESCRIPTION = "Decodes latent images back into pixel space images."
SHORT_DESCRIPTION = None
SEARCH_ALIASES = ["decode", "decode latent", "latent to image", "render latent"]
def decode(self, vae, samples):
@@ -329,6 +349,8 @@ class VAEDecodeTiled:
FUNCTION = "decode"
CATEGORY = "_for_testing"
DESCRIPTION = "Decodes latent images to pixel space using tiling to reduce memory usage, with configurable tile size, overlap, and temporal settings for video VAEs."
SHORT_DESCRIPTION = "Decodes latents to images using tiling for lower memory."
def decode(self, vae, samples, tile_size, overlap=64, temporal_size=64, temporal_overlap=8):
if tile_size < overlap * 4:
@@ -357,6 +379,8 @@ class VAEEncode:
FUNCTION = "encode"
CATEGORY = "latent"
DESCRIPTION = "Encodes pixel images into latent space using a VAE model."
SHORT_DESCRIPTION = None
SEARCH_ALIASES = ["encode", "encode image", "image to latent"]
def encode(self, vae, pixels):
@@ -376,6 +400,8 @@ class VAEEncodeTiled:
FUNCTION = "encode"
CATEGORY = "_for_testing"
DESCRIPTION = "Encodes pixel images into latent space using tiling to reduce memory usage, with configurable tile size, overlap, and temporal settings for video VAEs."
SHORT_DESCRIPTION = "Encodes images to latents using tiling for lower memory."
def encode(self, vae, pixels, tile_size, overlap, temporal_size=64, temporal_overlap=8):
t = vae.encode_tiled(pixels, tile_x=tile_size, tile_y=tile_size, overlap=overlap, tile_t=temporal_size, overlap_t=temporal_overlap)
@@ -389,6 +415,8 @@ class VAEEncodeForInpaint:
FUNCTION = "encode"
CATEGORY = "latent/inpaint"
DESCRIPTION = "Encodes an image into latent space for inpainting by applying and optionally growing a mask, zeroing out masked pixel regions before encoding."
SHORT_DESCRIPTION = "Encodes images for inpainting with mask-aware encoding."
def encode(self, vae, pixels, mask, grow_mask_by=6):
downscale_ratio = vae.spacial_compression_encode()
@@ -438,6 +466,8 @@ class InpaintModelConditioning:
FUNCTION = "encode"
CATEGORY = "conditioning/inpaint"
DESCRIPTION = "Prepares conditioning for inpaint models by encoding the masked image and concatenating the latent and mask information into the positive and negative conditioning."
SHORT_DESCRIPTION = "Prepares inpaint model conditioning with mask-aware latents."
def encode(self, positive, negative, pixels, vae, mask, noise_mask=True):
x = (pixels.shape[1] // 8) * 8
@@ -492,6 +522,8 @@ class SaveLatent:
OUTPUT_NODE = True
CATEGORY = "_for_testing"
DESCRIPTION = "Saves latent tensors to a safetensors file in the output directory with optional workflow metadata."
SHORT_DESCRIPTION = "Saves latent tensors to a safetensors file."
def save(self, samples, filename_prefix="ComfyUI", prompt=None, extra_pnginfo=None):
full_output_folder, filename, counter, subfolder, filename_prefix = folder_paths.get_save_image_path(filename_prefix, self.output_dir)
@@ -537,6 +569,8 @@ class LoadLatent:
return {"required": {"latent": [sorted(files), ]}, }
CATEGORY = "_for_testing"
DESCRIPTION = "Loads latent tensors from a previously saved safetensors file in the input directory."
SHORT_DESCRIPTION = "Loads latent tensors from a safetensors file."
RETURN_TYPES = ("LATENT", )
FUNCTION = "load"
@@ -576,6 +610,8 @@ class CheckpointLoader:
FUNCTION = "load_checkpoint"
CATEGORY = "advanced/loaders"
DESCRIPTION = "Loads a checkpoint using a separate model config file. Deprecated in favor of CheckpointLoaderSimple which auto-detects the config."
SHORT_DESCRIPTION = "Loads a checkpoint with a manual config file (deprecated)."
DEPRECATED = True
def load_checkpoint(self, config_name, ckpt_name):
@@ -599,6 +635,7 @@ class CheckpointLoaderSimple:
CATEGORY = "loaders"
DESCRIPTION = "Loads a diffusion model checkpoint, diffusion models are used to denoise latents."
SHORT_DESCRIPTION = "Loads a diffusion model checkpoint for denoising latents."
SEARCH_ALIASES = ["load model", "checkpoint", "model loader", "load checkpoint", "ckpt", "model"]
def load_checkpoint(self, ckpt_name):
@@ -623,6 +660,8 @@ class DiffusersLoader:
FUNCTION = "load_checkpoint"
CATEGORY = "advanced/loaders/deprecated"
DESCRIPTION = "Loads a diffusion model from the Hugging Face diffusers format, outputting the model, CLIP, and VAE components."
SHORT_DESCRIPTION = "Loads diffusers-format models into model, CLIP, and VAE."
def load_checkpoint(self, model_path, output_vae=True, output_clip=True):
for search_path in folder_paths.get_folder_paths("diffusers"):
@@ -644,6 +683,8 @@ class unCLIPCheckpointLoader:
FUNCTION = "load_checkpoint"
CATEGORY = "loaders"
DESCRIPTION = "Loads an unCLIP checkpoint, outputting the model, CLIP, VAE, and CLIP Vision components needed for image-guided generation."
SHORT_DESCRIPTION = "Loads unCLIP checkpoints with CLIP Vision output."
def load_checkpoint(self, ckpt_name, output_vae=True, output_clip=True):
ckpt_path = folder_paths.get_full_path_or_raise("checkpoints", ckpt_name)
@@ -660,6 +701,8 @@ class CLIPSetLastLayer:
FUNCTION = "set_last_layer"
CATEGORY = "conditioning"
DESCRIPTION = "Sets which CLIP layer to use as the output. Earlier layers (more negative values) can produce different stylistic effects."
SHORT_DESCRIPTION = "Sets which CLIP layer to use as output."
def set_last_layer(self, clip, stop_at_clip_layer):
clip = clip.clone()
@@ -688,6 +731,7 @@ class LoraLoader:
CATEGORY = "loaders"
DESCRIPTION = "LoRAs are used to modify diffusion and CLIP models, altering the way in which latents are denoised such as applying styles. Multiple LoRA nodes can be linked together."
SHORT_DESCRIPTION = "Modifies diffusion and CLIP models using LoRA adjustments."
SEARCH_ALIASES = ["lora", "load lora", "apply lora", "lora loader", "lora model"]
def load_lora(self, model, clip, lora_name, strength_model, strength_clip):
@@ -718,6 +762,8 @@ class LoraLoaderModelOnly(LoraLoader):
}}
RETURN_TYPES = ("MODEL",)
FUNCTION = "load_lora_model_only"
DESCRIPTION = "Loads a LoRA and applies it to the diffusion model only, without modifying the CLIP model."
SHORT_DESCRIPTION = "Applies a LoRA to the diffusion model only."
def load_lora_model_only(self, model, lora_name, strength_model):
return (self.load_lora(model, None, lora_name, strength_model, 0)[0],)
@@ -808,6 +854,8 @@ class VAELoader:
FUNCTION = "load_vae"
CATEGORY = "loaders"
DESCRIPTION = "Loads a VAE model for encoding and decoding images to and from latent space, supporting full VAEs, tiny autoencoders (TAESD), and video VAEs."
SHORT_DESCRIPTION = "Loads a VAE model for image encoding and decoding."
#TODO: scale factor?
def load_vae(self, vae_name):
@@ -836,6 +884,8 @@ class ControlNetLoader:
FUNCTION = "load_controlnet"
CATEGORY = "loaders"
DESCRIPTION = "Loads a ControlNet model from file for guiding image generation with structural conditioning."
SHORT_DESCRIPTION = "Loads a ControlNet model from file."
SEARCH_ALIASES = ["controlnet", "control net", "cn", "load controlnet", "controlnet loader"]
def load_controlnet(self, control_net_name):
@@ -855,6 +905,8 @@ class DiffControlNetLoader:
FUNCTION = "load_controlnet"
CATEGORY = "loaders"
DESCRIPTION = "Loads a differential ControlNet model that requires a base diffusion model for initialization."
SHORT_DESCRIPTION = "Loads a differential ControlNet with a base model."
def load_controlnet(self, model, control_net_name):
controlnet_path = folder_paths.get_full_path_or_raise("controlnet", control_net_name)
@@ -875,6 +927,8 @@ class ControlNetApply:
DEPRECATED = True
CATEGORY = "conditioning/controlnet"
DESCRIPTION = "Applies a ControlNet to conditioning with an image hint and strength. Deprecated in favor of ControlNetApplyAdvanced."
SHORT_DESCRIPTION = "Applies ControlNet to conditioning (deprecated)."
def apply_controlnet(self, conditioning, control_net, image, strength):
if strength == 0:
@@ -913,6 +967,8 @@ class ControlNetApplyAdvanced:
FUNCTION = "apply_controlnet"
CATEGORY = "conditioning/controlnet"
DESCRIPTION = "Applies a ControlNet to both positive and negative conditioning with an image hint, adjustable strength, and start/end percentage controls for scheduling."
SHORT_DESCRIPTION = "Applies ControlNet with strength and timestep scheduling."
SEARCH_ALIASES = ["controlnet", "apply controlnet", "use controlnet", "control net"]
def apply_controlnet(self, positive, negative, control_net, image, strength, start_percent, end_percent, vae=None, extra_concat=[]):
@@ -954,6 +1010,8 @@ class UNETLoader:
FUNCTION = "load_unet"
CATEGORY = "advanced/loaders"
DESCRIPTION = "Loads a standalone diffusion model (UNET/DiT) with optional weight dtype selection including fp8 precision modes for lower memory usage."
SHORT_DESCRIPTION = "Loads a diffusion model with optional fp8 precision."
def load_unet(self, unet_name, weight_dtype):
model_options = {}
@@ -984,6 +1042,7 @@ class CLIPLoader:
CATEGORY = "advanced/loaders"
DESCRIPTION = "[Recipes]\n\nstable_diffusion: clip-l\nstable_cascade: clip-g\nsd3: t5 xxl/ clip-g / clip-l\nstable_audio: t5 base\nmochi: t5 xxl\ncosmos: old t5 xxl\nlumina2: gemma 2 2B\nwan: umt5 xxl\n hidream: llama-3.1 (Recommend) or t5\nomnigen2: qwen vl 2.5 3B"
SHORT_DESCRIPTION = "Loads a single CLIP model with architecture-specific recipes."
def load_clip(self, clip_name, type="stable_diffusion", device="default"):
clip_type = getattr(comfy.sd.CLIPType, type.upper(), comfy.sd.CLIPType.STABLE_DIFFUSION)
@@ -1012,6 +1071,7 @@ class DualCLIPLoader:
CATEGORY = "advanced/loaders"
DESCRIPTION = "[Recipes]\n\nsdxl: clip-l, clip-g\nsd3: clip-l, clip-g / clip-l, t5 / clip-g, t5\nflux: clip-l, t5\nhidream: at least one of t5 or llama, recommended t5 and llama\nhunyuan_image: qwen2.5vl 7b and byt5 small\nnewbie: gemma-3-4b-it, jina clip v2"
SHORT_DESCRIPTION = "Loads two CLIP models simultaneously with architecture recipes."
def load_clip(self, clip_name1, clip_name2, type, device="default"):
clip_type = getattr(comfy.sd.CLIPType, type.upper(), comfy.sd.CLIPType.STABLE_DIFFUSION)
@@ -1035,6 +1095,8 @@ class CLIPVisionLoader:
FUNCTION = "load_clip"
CATEGORY = "loaders"
DESCRIPTION = "Loads a CLIP Vision model for encoding images into CLIP vision embeddings."
SHORT_DESCRIPTION = "Loads a CLIP Vision model for image encoding."
def load_clip(self, clip_name):
clip_path = folder_paths.get_full_path_or_raise("clip_vision", clip_name)
@@ -1054,6 +1116,8 @@ class CLIPVisionEncode:
FUNCTION = "encode"
CATEGORY = "conditioning"
DESCRIPTION = "Encodes an image using a CLIP Vision model to produce a vision embedding, with optional center cropping."
SHORT_DESCRIPTION = "Encodes images into CLIP Vision embeddings."
def encode(self, clip_vision, image, crop):
crop_image = True
@@ -1071,6 +1135,8 @@ class StyleModelLoader:
FUNCTION = "load_style_model"
CATEGORY = "loaders"
DESCRIPTION = "Loads a style model from file for applying visual styles to conditioning."
SHORT_DESCRIPTION = "Loads a style model from file."
def load_style_model(self, style_model_name):
style_model_path = folder_paths.get_full_path_or_raise("style_models", style_model_name)
@@ -1093,6 +1159,8 @@ class StyleModelApply:
FUNCTION = "apply_stylemodel"
CATEGORY = "conditioning/style_model"
DESCRIPTION = "Applies a style model to conditioning using a CLIP Vision output, with adjustable strength via multiply or attention bias modes."
SHORT_DESCRIPTION = "Applies a style model to conditioning with strength control."
def apply_stylemodel(self, conditioning, style_model, clip_vision_output, strength, strength_type):
cond = style_model.get_cond(clip_vision_output).flatten(start_dim=0, end_dim=1).unsqueeze(dim=0)
@@ -1153,6 +1221,8 @@ class unCLIPConditioning:
FUNCTION = "apply_adm"
CATEGORY = "conditioning"
DESCRIPTION = "Applies unCLIP image conditioning by adding CLIP vision embeddings to conditioning with adjustable strength and noise augmentation."
SHORT_DESCRIPTION = "Applies unCLIP image conditioning with vision embeddings."
def apply_adm(self, conditioning, clip_vision_output, strength, noise_augmentation):
if strength == 0:
@@ -1170,6 +1240,7 @@ class GLIGENLoader:
FUNCTION = "load_gligen"
CATEGORY = "loaders"
DESCRIPTION = "Loads a GLIGEN model for spatially-grounded text-to-image generation."
def load_gligen(self, gligen_name):
gligen_path = folder_paths.get_full_path_or_raise("gligen", gligen_name)
@@ -1192,6 +1263,8 @@ class GLIGENTextBoxApply:
FUNCTION = "append"
CATEGORY = "conditioning/gligen"
DESCRIPTION = "Applies GLIGEN text box conditioning to place a text-described object at a specific bounding box position in the generated image."
SHORT_DESCRIPTION = "Places a text-described object at a bounding box position."
def append(self, conditioning_to, clip, gligen_textbox_model, text, width, height, x, y):
c = []
@@ -1226,6 +1299,7 @@ class EmptyLatentImage:
CATEGORY = "latent"
DESCRIPTION = "Create a new batch of empty latent images to be denoised via sampling."
SHORT_DESCRIPTION = "Creates empty latent images for denoising via sampling."
SEARCH_ALIASES = ["empty", "empty latent", "new latent", "create latent", "blank latent", "blank"]
def generate(self, width, height, batch_size=1):
@@ -1246,6 +1320,8 @@ class LatentFromBatch:
FUNCTION = "frombatch"
CATEGORY = "latent/batch"
DESCRIPTION = "Extracts a contiguous range of samples from a latent batch by specifying a start index and length."
SHORT_DESCRIPTION = "Extracts a range of samples from a latent batch."
def frombatch(self, samples, batch_index, length):
s = samples.copy()
@@ -1279,6 +1355,8 @@ class RepeatLatentBatch:
FUNCTION = "repeat"
CATEGORY = "latent/batch"
DESCRIPTION = "Repeats a latent batch a specified number of times to create a larger batch."
SHORT_DESCRIPTION = "Duplicates latent batch samples a specified number of times."
def repeat(self, samples, amount):
s = samples.copy()
@@ -1311,6 +1389,8 @@ class LatentUpscale:
FUNCTION = "upscale"
CATEGORY = "latent"
DESCRIPTION = "Upscales latent representations to a target width and height using various interpolation methods, with optional cropping."
SHORT_DESCRIPTION = "Upscales latents to a target resolution."
def upscale(self, samples, upscale_method, width, height, crop):
if width == 0 and height == 0:
@@ -1344,6 +1424,7 @@ class LatentUpscaleBy:
FUNCTION = "upscale"
CATEGORY = "latent"
DESCRIPTION = "Upscales latent representations by a relative scale factor using various interpolation methods."
def upscale(self, samples, upscale_method, scale_by):
s = samples.copy()
@@ -1362,6 +1443,8 @@ class LatentRotate:
FUNCTION = "rotate"
CATEGORY = "latent/transform"
DESCRIPTION = "Rotates latent representations by 90, 180, or 270 degrees."
SHORT_DESCRIPTION = None
def rotate(self, samples, rotation):
s = samples.copy()
@@ -1388,6 +1471,8 @@ class LatentFlip:
FUNCTION = "flip"
CATEGORY = "latent/transform"
DESCRIPTION = "Flips latent representations vertically or horizontally."
SHORT_DESCRIPTION = None
def flip(self, samples, flip_method):
s = samples.copy()
@@ -1413,6 +1498,8 @@ class LatentComposite:
FUNCTION = "composite"
CATEGORY = "latent"
DESCRIPTION = "Composites one latent onto another at a specified position with optional feathered blending at the edges."
SHORT_DESCRIPTION = "Composites one latent onto another with feathering."
def composite(self, samples_to, samples_from, x, y, composite_method="normal", feather=0):
x = x // 8
@@ -1462,6 +1549,8 @@ class LatentBlend:
FUNCTION = "blend"
CATEGORY = "_for_testing"
DESCRIPTION = "Blends two latent representations together using a blend factor, automatically resizing if dimensions differ."
SHORT_DESCRIPTION = "Blends two latents together using a blend factor."
def blend(self, samples1, samples2, blend_factor:float, blend_mode: str="normal"):
@@ -1500,6 +1589,8 @@ class LatentCrop:
FUNCTION = "crop"
CATEGORY = "latent/transform"
DESCRIPTION = "Crops a latent representation to a specified width, height, and position."
SHORT_DESCRIPTION = None
def crop(self, samples, width, height, x, y):
s = samples.copy()
@@ -1530,6 +1621,8 @@ class SetLatentNoiseMask:
FUNCTION = "set_mask"
CATEGORY = "latent/inpaint"
DESCRIPTION = "Sets a noise mask on a latent so that sampling only adds noise within the masked region, used for inpainting workflows."
SHORT_DESCRIPTION = "Sets a noise mask on latent for inpainting."
def set_mask(self, samples, mask):
s = samples.copy()
@@ -1584,6 +1677,7 @@ class KSampler:
CATEGORY = "sampling"
DESCRIPTION = "Uses the provided model, positive and negative conditioning to denoise the latent image."
SHORT_DESCRIPTION = "Denoises latent images using model and conditioning inputs."
SEARCH_ALIASES = ["sampler", "sample", "generate", "denoise", "diffuse", "txt2img", "img2img"]
def sample(self, model, seed, steps, cfg, sampler_name, scheduler, positive, negative, latent_image, denoise=1.0):
@@ -1613,6 +1707,8 @@ class KSamplerAdvanced:
FUNCTION = "sample"
CATEGORY = "sampling"
DESCRIPTION = "Advanced sampler with fine-grained control over noise addition, start/end steps, and whether to return with leftover noise for multi-pass sampling."
SHORT_DESCRIPTION = "Advanced sampler with step range and noise controls."
def sample(self, model, add_noise, noise_seed, steps, cfg, sampler_name, scheduler, positive, negative, latent_image, start_at_step, end_at_step, return_with_leftover_noise, denoise=1.0):
force_full_denoise = True
@@ -1649,6 +1745,7 @@ class SaveImage:
CATEGORY = "image"
DESCRIPTION = "Saves the input images to your ComfyUI output directory."
SHORT_DESCRIPTION = None
SEARCH_ALIASES = ["save", "save image", "export image", "output image", "write image", "download"]
def save_images(self, images, filename_prefix="ComfyUI", prompt=None, extra_pnginfo=None):
@@ -1687,6 +1784,8 @@ class PreviewImage(SaveImage):
self.compress_level = 1
SEARCH_ALIASES = ["preview", "preview image", "show image", "view image", "display image", "image viewer"]
DESCRIPTION = "Previews images in the UI by saving them as temporary files that are not permanently stored."
SHORT_DESCRIPTION = "Previews images in the UI as temporary files."
@classmethod
def INPUT_TYPES(s):
@@ -1706,6 +1805,8 @@ class LoadImage:
}
CATEGORY = "image"
DESCRIPTION = "Loads an image from the input directory, supporting animated formats and alpha channel extraction as a mask output."
SHORT_DESCRIPTION = "Loads an image file with optional alpha mask output."
SEARCH_ALIASES = ["load image", "open image", "import image", "image input", "upload image", "read image", "image loader"]
RETURN_TYPES = ("IMAGE", "MASK")
@@ -1787,6 +1888,8 @@ class LoadImageMask:
}
CATEGORY = "mask"
DESCRIPTION = "Loads an image and extracts a specific color channel as a mask."
SHORT_DESCRIPTION = "Loads an image channel as a mask."
RETURN_TYPES = ("MASK",)
FUNCTION = "load_image"
@@ -1845,6 +1948,7 @@ class LoadImageOutput(LoadImage):
}
DESCRIPTION = "Load an image from the output folder. When the refresh button is clicked, the node will update the image list and automatically select the first image, allowing for easy iteration."
SHORT_DESCRIPTION = "Loads images from the output folder with auto-refresh."
EXPERIMENTAL = True
FUNCTION = "load_image"
@@ -1863,6 +1967,8 @@ class ImageScale:
FUNCTION = "upscale"
CATEGORY = "image/upscaling"
DESCRIPTION = "Scales an image to a target width and height using various interpolation methods, with optional center cropping."
SHORT_DESCRIPTION = "Scales images to a target width and height."
SEARCH_ALIASES = ["resize", "resize image", "scale image", "image resize", "zoom", "zoom in", "change size"]
def upscale(self, image, upscale_method, width, height, crop):
@@ -1891,6 +1997,8 @@ class ImageScaleBy:
FUNCTION = "upscale"
CATEGORY = "image/upscaling"
DESCRIPTION = "Scales an image by a relative factor using various interpolation methods."
SHORT_DESCRIPTION = None
def upscale(self, image, upscale_method, scale_by):
samples = image.movedim(-1,1)
@@ -1911,6 +2019,8 @@ class ImageInvert:
FUNCTION = "invert"
CATEGORY = "image"
DESCRIPTION = "Inverts image colors by subtracting each pixel value from 1.0."
SHORT_DESCRIPTION = None
def invert(self, image):
s = 1.0 - image
@@ -1927,6 +2037,8 @@ class ImageBatch:
FUNCTION = "batch"
CATEGORY = "image"
DESCRIPTION = "Batches two images together into a single batch, automatically resizing if dimensions differ. Deprecated in favor of the general-purpose Batch node."
SHORT_DESCRIPTION = "Batches two images together (deprecated)."
DEPRECATED = True
def batch(self, image1, image2):
@@ -1955,6 +2067,8 @@ class EmptyImage:
FUNCTION = "generate"
CATEGORY = "image"
DESCRIPTION = "Creates a batch of blank images filled with a specified color at the given dimensions."
SHORT_DESCRIPTION = "Creates blank images filled with a solid color."
def generate(self, width, height, batch_size=1, color=0):
r = torch.full([batch_size, height, width, 1], ((color >> 16) & 0xFF) / 0xFF)
@@ -1982,6 +2096,8 @@ class ImagePadForOutpaint:
FUNCTION = "expand_image"
CATEGORY = "image"
DESCRIPTION = "Pads an image on all sides for outpainting, generating a feathered mask that blends the original image edges into the new padded area."
SHORT_DESCRIPTION = "Pads images with feathered mask for outpainting."
def expand_image(self, image, left, top, right, bottom, feathering):
d1, d2, d3, d4 = image.size()