diff --git a/load_image_list.py b/load_image_list.py index c9c3cac..24a2066 100644 --- a/load_image_list.py +++ b/load_image_list.py @@ -32,6 +32,12 @@ class BatchLoadImageList: RETURN_TYPES = ("IMAGE", "INT") FUNCTION = "execute" + DESCRIPTION = """ +Loads images from a provided list of paths. +- Best used with `Batch Save Image Sequence` output. +- Supports slicing (start, end, step) for partial loading. +- Optimized with async loading and direct tensor conversion. +""" def execute( self, diff --git a/load_image_sequence.py b/load_image_sequence.py index fdf7b92..d540fdd 100644 --- a/load_image_sequence.py +++ b/load_image_sequence.py @@ -26,13 +26,20 @@ class BatchLoadImageSequence: {"default": "./frame{:06d}.webp", "multiline": False}, ), "start_index": ("INT", {"default": 0, "min": 0, "step": 1}), - "frame_count": ("INT", {"default": 16, "min": 1, "step": 1}), + "frame_count": ("INT", {"default": 16, "min": 0, "step": 1}), "ignore_missing_images": (("false", "true"), {"default": "false"}), } } RETURN_TYPES = ("IMAGE", "INT") FUNCTION = "execute" + DESCRIPTION = """ +Loads a sequence of images from disk using a pattern. +- Supports high-performance async loading. +- Ideal for loading rendered sequences or datasets. +- Use pattern like `frame{:06d}.webp` to match filenames. +- Set `frame_count` to 0 to auto-detect all available frames (contiguous). +""" def execute( self, @@ -42,20 +49,40 @@ class BatchLoadImageSequence: ignore_missing_images: str, ): ignore_missing_images = ignore_missing_images == "true" - image_paths = [] - for i in range(start_index, start_index + frame_count): - try: - image_paths.append(path_pattern.format(i)) - except KeyError: - image_paths.append(path_pattern.format(i=i)) - if ignore_missing_images: - image_paths = [p for p in image_paths if os.path.exists(p)] + if frame_count == 0: + # Auto-detect mode: load all contiguous frames starting from start_index + i = start_index + while True: + try: + p = path_pattern.format(i) + except KeyError: + p = path_pattern.format(i=i) + + if not os.path.exists(p): + break + + image_paths.append(p) + i += 1 + + # Safety break to avoid infinite loops if something weird happens (e.g. symlink loops? unlikely but good practice) + if len(image_paths) > 100000: + break else: - for path in image_paths: - if not os.path.exists(path): - raise FileNotFoundError(f"Image does not exist: {path}") + # Standard Fixed Count Mode + for i in range(start_index, start_index + frame_count): + try: + image_paths.append(path_pattern.format(i)) + except KeyError: + image_paths.append(path_pattern.format(i=i)) + + if ignore_missing_images: + image_paths = [p for p in image_paths if os.path.exists(p)] + else: + for path in image_paths: + if not os.path.exists(path): + raise FileNotFoundError(f"Image does not exist: {path}") if len(image_paths) == 0: raise RuntimeError("Image sequence empty - no images to load") @@ -74,10 +101,35 @@ class BatchLoadImageSequence: return (torch.cat(imgs, dim=0), len(imgs)) + +class BatchLoadImageSequenceWithTrigger(BatchLoadImageSequence): + @classmethod + def INPUT_TYPES(cls): + inputs = BatchLoadImageSequence.INPUT_TYPES() + inputs["optional"] = { + "trigger": ("*", {}), # Any type trigger + } + return inputs + + RETURN_TYPES = ("IMAGE", "INT") + FUNCTION = "execute_with_trigger" + + DESCRIPTION = """ +Same as BatchLoadImageSequence but with an optional trigger input. +- Connect any output to `trigger` to force this node to wait. +- Useful for ensuring a process finishes before loading starts. +""" + + def execute_with_trigger(self, path_pattern, start_index, frame_count, ignore_missing_images, trigger=None): + return self.execute(path_pattern, start_index, frame_count, ignore_missing_images) + + NODE_CLASS_MAPPINGS = { - "BatchLoadImageSequence": BatchLoadImageSequence + "BatchLoadImageSequence": BatchLoadImageSequence, + "BatchLoadImageSequenceWithTrigger": BatchLoadImageSequenceWithTrigger, } NODE_DISPLAY_NAME_MAPPINGS = { - "BatchLoadImageSequence": "Batch Load Image Sequence" + "BatchLoadImageSequence": "Batch Load Image Sequence", + "BatchLoadImageSequenceWithTrigger": "Batch Load Image Sequence (Trigger)", } diff --git a/save_webp_sequence.py b/save_webp_sequence.py index e582acd..ec7643c 100644 --- a/save_webp_sequence.py +++ b/save_webp_sequence.py @@ -35,6 +35,13 @@ class BatchSaveImageSequenceWebP: RETURN_TYPES = ("STRING_LIST", "INT") RETURN_NAMES = ("paths", "count") FUNCTION = "execute" + DESCRIPTION = """ +Saves a batch of images as a WebP sequence. +- Optimized for long sequences with async saving. +- Supports lossy and lossless compression. +- Can skip identical frames to save space. +- Restricted to ComfyUI output directory for security. +""" def execute( self,