Save Gif (mtb)¶
Documentation¶
- Class name:
Save Gif (mtb)
- Category:
mtb/IO
- Output node:
True
This node is designed to save a sequence of images as a GIF file, offering customization options such as frame rate, size adjustment, optimization, and the choice between a standard saving method or using FFmpeg for potentially enhanced performance.
Input types¶
Required¶
image
- The sequence of images to be saved as a GIF. This is the primary input that dictates the content of the resulting GIF file.
- Comfy dtype:
IMAGE
- Python dtype:
torch.Tensor
fps
- Specifies the frames per second for the GIF, controlling how fast the images in the sequence are played back.
- Comfy dtype:
INT
- Python dtype:
int
resize_by
- A scaling factor to adjust the size of the images in the GIF, with 1.0 meaning no scaling.
- Comfy dtype:
FLOAT
- Python dtype:
float
optimize
- A boolean indicating whether to apply optimization to the GIF, which can reduce file size at the cost of potentially longer processing times.
- Comfy dtype:
BOOLEAN
- Python dtype:
bool
pingpong
- When enabled, the GIF animation will play forwards and then backwards, creating a seamless loop effect.
- Comfy dtype:
BOOLEAN
- Python dtype:
bool
resample_filter
- The resampling filter to use when resizing images, affecting the quality of the resized images.
- Comfy dtype:
COMBO[STRING]
- Python dtype:
Optional[str]
use_ffmpeg
- A boolean indicating whether to use FFmpeg for GIF creation, which can offer more efficient processing for certain types of content.
- Comfy dtype:
BOOLEAN
- Python dtype:
bool
Output types¶
ui
- Returns a UI element with the generated GIF, including the filename and path where the GIF is saved.
Usage tips¶
- Infra type:
CPU
- Common nodes: unknown
Source code¶
class MTB_SaveGif:
"""Save the images from the batch as a GIF"""
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"image": ("IMAGE",),
"fps": ("INT", {"default": 12, "min": 1, "max": 120}),
"resize_by": ("FLOAT", {"default": 1.0, "min": 0.1}),
"optimize": ("BOOLEAN", {"default": False}),
"pingpong": ("BOOLEAN", {"default": False}),
"resample_filter": (list(PIL_FILTER_MAP.keys()),),
"use_ffmpeg": ("BOOLEAN", {"default": False}),
},
}
RETURN_TYPES = ()
OUTPUT_NODE = True
CATEGORY = "mtb/IO"
FUNCTION = "save_gif"
def save_gif(
self,
image,
fps=12,
resize_by=1.0,
optimize=False,
pingpong=False,
resample_filter=None,
use_ffmpeg=False,
):
if image.size(0) == 0:
return ("",)
if resample_filter is not None:
resample_filter = PIL_FILTER_MAP.get(resample_filter)
pil_images = prepare_animated_batch(
image,
pingpong,
resize_by,
resample_filter,
)
ruuid = uuid.uuid4()
ruuid = ruuid.hex[:10]
out_path = f"{folder_paths.output_directory}/{ruuid}.gif"
if use_ffmpeg:
# Use FFmpeg to create the GIF from PIL images
command = [
"ffmpeg",
"-f",
"image2pipe",
"-vcodec",
"png",
"-r",
str(fps),
"-i",
"-",
"-vcodec",
"gif",
"-y",
out_path,
]
process = subprocess.Popen(command, stdin=subprocess.PIPE)
for image in pil_images:
model_management.throw_exception_if_processing_interrupted()
image.save(process.stdin, "PNG")
process.stdin.close()
process.wait()
else:
pil_images[0].save(
out_path,
save_all=True,
append_images=pil_images[1:],
optimize=optimize,
duration=int(1000 / fps),
loop=0,
)
results = [
{"filename": f"{ruuid}.gif", "subfolder": "", "type": "output"}
]
return {"ui": {"gif": results}}