Skip to content

Save Image Sequence (mtb)

Documentation

  • Class name: Save Image Sequence (mtb)
  • Category: mtb/IO
  • Output node: True

The Save Image Sequence node is designed to save a sequence of images to a specified directory, allowing for the inclusion of additional metadata such as prompts and custom PNG information. It facilitates the organization and storage of generated image sequences, making it easier to retrieve and utilize them for further processing or presentation.

Input types

Required

  • images
    • The sequence of images to be saved. This parameter is crucial as it directly influences the node's primary function of storing these images in a specified format and location.
    • Comfy dtype: IMAGE
    • Python dtype: List[torch.Tensor]
  • filename_prefix
    • A prefix for the filename under which the images will be saved. This allows for easy identification and organization of saved images within the output directory.
    • Comfy dtype: STRING
    • Python dtype: str
  • current_frame
    • Indicates the starting point or current frame number for the sequence of images being saved. This helps in organizing the sequence and maintaining continuity if the sequence is being updated over time.
    • Comfy dtype: INT
    • Python dtype: int

Output types

The node doesn't have output types

Usage tips

  • Infra type: CPU
  • Common nodes: unknown

Source code

class MTB_SaveImageSequence:
    """Save an image sequence to a folder. The current frame is used to determine which image to save.

    This is merely a wrapper around the `save_images` function with formatting for the output folder and filename.
    """

    def __init__(self):
        self.output_dir = folder_paths.get_output_directory()
        self.type = "output"

    @classmethod
    def INPUT_TYPES(cls):
        return {
            "required": {
                "images": ("IMAGE",),
                "filename_prefix": ("STRING", {"default": "Sequence"}),
                "current_frame": (
                    "INT",
                    {"default": 0, "min": 0, "max": 9999999},
                ),
            },
            "hidden": {"prompt": "PROMPT", "extra_pnginfo": "EXTRA_PNGINFO"},
        }

    RETURN_TYPES = ()
    FUNCTION = "save_images"

    OUTPUT_NODE = True

    CATEGORY = "mtb/IO"

    def save_images(
        self,
        images,
        filename_prefix="Sequence",
        current_frame=0,
        prompt=None,
        extra_pnginfo=None,
    ):
        # full_output_folder, filename, counter, subfolder, filename_prefix = folder_paths.get_save_image_path(filename_prefix, self.output_dir, images[0].shape[1], images[0].shape[0])
        # results = list()
        # for image in images:
        #     i = 255. * image.cpu().numpy()
        #     img = Image.fromarray(np.clip(i, 0, 255).astype(np.uint8))
        #     metadata = PngInfo()
        #     if prompt is not None:
        #         metadata.add_text("prompt", json.dumps(prompt))
        #     if extra_pnginfo is not None:
        #         for x in extra_pnginfo:
        #             metadata.add_text(x, json.dumps(extra_pnginfo[x]))

        #     file = f"{filename}_{counter:05}_.png"
        #     img.save(os.path.join(full_output_folder, file), pnginfo=metadata, compress_level=4)
        #     results.append({
        #         "filename": file,
        #         "subfolder": subfolder,
        #         "type": self.type
        #     })
        #     counter += 1

        if len(images) > 1:
            raise ValueError("Can only save one image at a time")

        resolved_path = Path(self.output_dir) / filename_prefix
        resolved_path.mkdir(parents=True, exist_ok=True)

        resolved_img = (
            resolved_path / f"{filename_prefix}_{current_frame:05}.png"
        )

        output_image = images[0].cpu().numpy()
        img = Image.fromarray(
            np.clip(output_image * 255.0, 0, 255).astype(np.uint8)
        )
        metadata = PngInfo()
        if prompt is not None:
            metadata.add_text("prompt", json.dumps(prompt))
        if extra_pnginfo is not None:
            for x in extra_pnginfo:
                metadata.add_text(x, json.dumps(extra_pnginfo[x]))

        img.save(resolved_img, pnginfo=metadata, compress_level=4)
        return {
            "ui": {
                "images": [
                    {
                        "filename": resolved_img.name,
                        "subfolder": resolved_path.name,
                        "type": self.type,
                    }
                ]
            }
        }