Create Grid Image¶
Documentation¶
- Class name:
Create Grid Image
- Category:
WAS Suite/Image/Process
- Output node:
False
This node is designed to create a grid image from a collection of image files. It allows for customization of the grid layout, including the number of columns, cell size, and border properties. The node supports filtering images by file extension and can include images from subfolders based on the user's choice.
Input types¶
Required¶
images_path
- The path to the directory containing the images to be included in the grid. The node checks for the existence of this path and filters images based on allowed extensions.
- Comfy dtype:
STRING
- Python dtype:
str
pattern_glob
- A glob pattern to filter the images in the specified path. It allows for more granular control over which images are included based on their filenames.
- Comfy dtype:
STRING
- Python dtype:
str
include_subfolders
- A flag indicating whether to include images from subdirectories of the specified path. This allows for recursive image inclusion based on the user's preference.
- Comfy dtype:
COMBO[STRING]
- Python dtype:
str
border_width
- The width of the border around each image in the grid. A width of 0 or less means no border is added.
- Comfy dtype:
INT
- Python dtype:
int
number_of_columns
- Specifies the number of columns in the grid layout. This affects the overall arrangement and appearance of the grid image.
- Comfy dtype:
INT
- Python dtype:
int
max_cell_size
- The maximum size for each cell in the grid, controlling the dimensions of the images in the grid.
- Comfy dtype:
INT
- Python dtype:
int
border_red
- The red component of the border color, allowing for customization of the border's appearance.
- Comfy dtype:
INT
- Python dtype:
int
border_green
- The green component of the border color, contributing to the customization of the border's appearance.
- Comfy dtype:
INT
- Python dtype:
int
border_blue
- The blue component of the border color, further allowing for customization of the border's appearance.
- Comfy dtype:
INT
- Python dtype:
int
Output types¶
image
- Comfy dtype:
IMAGE
- The generated grid image as a tensor, suitable for further processing or visualization.
- Python dtype:
torch.Tensor
- Comfy dtype:
Usage tips¶
- Infra type:
GPU
- Common nodes: unknown
Source code¶
class WAS_Image_Grid_Image:
def __init__(self):
pass
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"images_path": ("STRING", {"default":"./ComfyUI/input/", "multiline": False}),
"pattern_glob": ("STRING", {"default":"*", "multiline": False}),
"include_subfolders": (["false", "true"],),
"border_width": ("INT", {"default":3, "min": 0, "max": 100, "step":1}),
"number_of_columns": ("INT", {"default":6, "min": 1, "max": 24, "step":1}),
"max_cell_size": ("INT", {"default":256, "min":32, "max":1280, "step":1}),
"border_red": ("INT", {"default":0, "min": 0, "max": 255, "step":1}),
"border_green": ("INT", {"default":0, "min": 0, "max": 255, "step":1}),
"border_blue": ("INT", {"default":0, "min": 0, "max": 255, "step":1}),
}
}
RETURN_TYPES = ("IMAGE",)
FUNCTION = "create_grid_image"
CATEGORY = "WAS Suite/Image/Process"
def create_grid_image(self, images_path, pattern_glob="*", include_subfolders="false", number_of_columns=6,
max_cell_size=256, border_width=3, border_red=0, border_green=0, border_blue=0):
if not os.path.exists(images_path):
cstr(f"The grid image path `{images_path}` does not exist!").error.print()
return (pil2tensor(Image.new("RGB", (512,512), (0,0,0))),)
paths = glob.glob(os.path.join(images_path, pattern_glob), recursive=(False if include_subfolders == "false" else True))
image_paths = []
for path in paths:
if path.lower().endswith(ALLOWED_EXT) and os.path.exists(path):
image_paths.append(path)
grid_image = self.smart_grid_image(image_paths, int(number_of_columns), (int(max_cell_size), int(max_cell_size)),
(False if border_width <= 0 else True), (int(border_red),
int(border_green), int(border_blue)), int(border_width))
return (pil2tensor(grid_image),)
def smart_grid_image(self, images, cols=6, size=(256,256), add_border=False, border_color=(0,0,0), border_width=3):
# calculate row height
max_width, max_height = size
row_height = 0
images_resized = []
for image in images:
img = Image.open(image).convert('RGB')
img_w, img_h = img.size
aspect_ratio = img_w / img_h
if aspect_ratio > 1: # landscape
thumb_w = min(max_width, img_w-border_width)
thumb_h = thumb_w / aspect_ratio
else: # portrait
thumb_h = min(max_height, img_h-border_width)
thumb_w = thumb_h * aspect_ratio
# pad the image to match the maximum size and center it within the cell
pad_w = max_width - int(thumb_w)
pad_h = max_height - int(thumb_h)
left = pad_w // 2
top = pad_h // 2
right = pad_w - left
bottom = pad_h - top
padding = (left, top, right, bottom) # left, top, right, bottom
img_resized = ImageOps.expand(img.resize((int(thumb_w), int(thumb_h))), padding)
if add_border:
img_resized_bordered = ImageOps.expand(img_resized, border=border_width//2, fill=border_color)
images_resized.append(img_resized)
row_height = max(row_height, img_resized.size[1])
row_height = int(row_height)
# calculate the number of rows
total_images = len(images_resized)
rows = math.ceil(total_images / cols)
# create empty image to put thumbnails
new_image = Image.new('RGB', (cols*size[0]+(cols-1)*border_width, rows*row_height+(rows-1)*border_width), border_color)
for i, img in enumerate(images_resized):
if add_border:
border_img = ImageOps.expand(img, border=border_width//2, fill=border_color)
x = (i % cols) * (size[0]+border_width)
y = (i // cols) * (row_height+border_width)
if border_img.size == (size[0], size[1]):
new_image.paste(border_img, (x, y, x+size[0], y+size[1]))
else:
# Resize image to match size parameter
border_img = border_img.resize((size[0], size[1]))
new_image.paste(border_img, (x, y, x+size[0], y+size[1]))
else:
x = (i % cols) * (size[0]+border_width)
y = (i // cols) * (row_height+border_width)
if img.size == (size[0], size[1]):
new_image.paste(img, (x, y, x+img.size[0], y+img.size[1]))
else:
# Resize image to match size parameter
img = img.resize((size[0], size[1]))
new_image.paste(img, (x, y, x+size[0], y+size[1]))
new_image = ImageOps.expand(new_image, border=border_width, fill=border_color)
return new_image