refactored Preview/Save of images

This commit is contained in:
bigcat88 2025-07-23 06:54:15 +03:00
parent 941dea9439
commit 333d942f30
No known key found for this signature in database
GPG Key ID: 1F0BF0EC3CF22721
2 changed files with 86 additions and 31 deletions

View File

@ -37,6 +37,20 @@ class SavedResult(dict):
return FolderType(self["type"]) return FolderType(self["type"])
class SavedImages(_UIOutput):
"""A UI output class to represent one or more saved images, potentially animated."""
def __init__(self, results: list[SavedResult], is_animated: bool = False):
super().__init__()
self.results = results
self.is_animated = is_animated
def as_dict(self) -> dict:
data = {"images": self.results}
if self.is_animated:
data["animated"] = (True,)
return data
def _get_directory_by_folder_type(folder_type: FolderType) -> str: def _get_directory_by_folder_type(folder_type: FolderType) -> str:
if folder_type == FolderType.input: if folder_type == FolderType.input:
return folder_paths.get_input_directory() return folder_paths.get_input_directory()
@ -125,14 +139,22 @@ class ImageSaveHelper:
counter += 1 counter += 1
return results return results
@staticmethod
def get_save_images_ui(images, filename_prefix: str, cls: Type[ComfyNodeV3] | None, compress_level=4) -> SavedImages:
"""Saves a batch of images and returns a UI object for the node output."""
return SavedImages(
ImageSaveHelper.save_images(
images,
filename_prefix=filename_prefix,
folder_type=FolderType.output,
cls=cls,
compress_level=compress_level,
)
)
@staticmethod @staticmethod
def save_animated_png( def save_animated_png(
images, images, filename_prefix: str, folder_type: FolderType, cls: Type[ComfyNodeV3] | None, fps: float, compress_level: int
filename_prefix: str,
folder_type: FolderType,
cls: Type[ComfyNodeV3] | None,
fps: float,
compress_level: int
) -> SavedResult: ) -> SavedResult:
"""Saves a batch of images as a single animated PNG.""" """Saves a batch of images as a single animated PNG."""
full_output_folder, filename, counter, subfolder, _ = folder_paths.get_save_image_path( full_output_folder, filename, counter, subfolder, _ = folder_paths.get_save_image_path(
@ -152,6 +174,21 @@ class ImageSaveHelper:
) )
return SavedResult(file, subfolder, folder_type) return SavedResult(file, subfolder, folder_type)
@staticmethod
def get_save_animated_png_ui(
images, filename_prefix: str, cls: Type[ComfyNodeV3] | None, fps: float, compress_level: int
) -> SavedImages:
"""Saves an animated PNG and returns a UI object for the node output."""
result = ImageSaveHelper.save_animated_png(
images,
filename_prefix=filename_prefix,
folder_type=FolderType.output,
cls=cls,
fps=fps,
compress_level=compress_level,
)
return SavedImages([result], is_animated=len(images) > 1)
@staticmethod @staticmethod
def save_animated_webp( def save_animated_webp(
images, images,
@ -182,6 +219,29 @@ class ImageSaveHelper:
) )
return SavedResult(file, subfolder, folder_type) return SavedResult(file, subfolder, folder_type)
@staticmethod
def get_save_animated_webp_ui(
images,
filename_prefix: str,
cls: Type[ComfyNodeV3] | None,
fps: float,
lossless: bool,
quality: int,
method: int,
) -> SavedImages:
"""Saves an animated WebP and returns a UI object for the node output."""
result = ImageSaveHelper.save_animated_webp(
images,
filename_prefix=filename_prefix,
folder_type=FolderType.output,
cls=cls,
fps=fps,
lossless=lossless,
quality=quality,
method=method,
)
return SavedImages([result], is_animated=len(images) > 1)
class PreviewImage(_UIOutput): class PreviewImage(_UIOutput):
def __init__(self, image: Image.Type, animated: bool=False, cls: ComfyNodeV3=None, **kwargs): def __init__(self, image: Image.Type, animated: bool=False, cls: ComfyNodeV3=None, **kwargs):

View File

@ -630,15 +630,15 @@ class SaveAnimatedPNG(io.ComfyNodeV3):
@classmethod @classmethod
def execute(cls, images, fps, compress_level, filename_prefix="ComfyUI") -> io.NodeOutput: def execute(cls, images, fps, compress_level, filename_prefix="ComfyUI") -> io.NodeOutput:
result = ui.ImageSaveHelper.save_animated_png( return io.NodeOutput(
images=images, ui=ui.ImageSaveHelper.get_save_animated_png_ui(
filename_prefix=filename_prefix, images=images,
folder_type=io.FolderType.output, filename_prefix=filename_prefix,
cls=cls, cls=cls,
fps=fps, fps=fps,
compress_level=compress_level, compress_level=compress_level,
)
) )
return io.NodeOutput(ui={"images": [result], "animated": (len(images) != 1,)})
class SaveAnimatedWEBP(io.ComfyNodeV3): class SaveAnimatedWEBP(io.ComfyNodeV3):
@ -664,17 +664,17 @@ class SaveAnimatedWEBP(io.ComfyNodeV3):
@classmethod @classmethod
def execute(cls, images, fps, filename_prefix, lossless, quality, method) -> io.NodeOutput: def execute(cls, images, fps, filename_prefix, lossless, quality, method) -> io.NodeOutput:
result = ui.ImageSaveHelper.save_animated_webp( return io.NodeOutput(
images=images, ui=ui.ImageSaveHelper.get_save_animated_webp_ui(
filename_prefix=filename_prefix, images=images,
folder_type=io.FolderType.output, filename_prefix=filename_prefix,
cls=cls, cls=cls,
fps=fps, fps=fps,
lossless=lossless, lossless=lossless,
quality=quality, quality=quality,
method=cls.COMPRESS_METHODS.get(method) method=cls.COMPRESS_METHODS.get(method)
)
) )
return io.NodeOutput(ui={"images": [result], "animated": (len(images) != 1,)})
class SaveImage(io.ComfyNodeV3): class SaveImage(io.ComfyNodeV3):
@ -703,14 +703,9 @@ class SaveImage(io.ComfyNodeV3):
@classmethod @classmethod
def execute(cls, images, filename_prefix="ComfyUI") -> io.NodeOutput: def execute(cls, images, filename_prefix="ComfyUI") -> io.NodeOutput:
results = ui.ImageSaveHelper.save_images( return io.NodeOutput(
images, ui=ui.ImageSaveHelper.get_save_images_ui(images, filename_prefix=filename_prefix, cls=cls, compress_level=4)
filename_prefix=filename_prefix,
folder_type=io.FolderType.output,
cls=cls,
compress_level=4,
) )
return io.NodeOutput(ui={"images": results})
NODES_LIST: list[type[io.ComfyNodeV3]] = [ NODES_LIST: list[type[io.ComfyNodeV3]] = [