added the ability to schedule some values in the FX nodes, as well as optimized some code to make them a little faster. Iv also added a % complete print in the console so you can see how far along the processing is =)
111 lines
4.9 KiB
Python
111 lines
4.9 KiB
Python
import torch
|
|
import numpy as np
|
|
from PIL import Image, ImageDraw
|
|
import math
|
|
import sys
|
|
|
|
class FL_HexagonalPattern:
|
|
def __init__(self):
|
|
self.hexagon_size_index = 0
|
|
self.shadow_offset_index = 0
|
|
self.shadow_color_index = 0
|
|
self.background_color_index = 0
|
|
self.rotation_index = 0
|
|
self.spacing_index = 0
|
|
|
|
@classmethod
|
|
def INPUT_TYPES(cls):
|
|
return {
|
|
"required": {
|
|
"images": ("IMAGE",),
|
|
},
|
|
"optional": {
|
|
"hexagon_size": ("INT", {"default": 100, "min": 50, "max": 500, "step": 10}),
|
|
"shadow_offset": ("INT", {"default": 5, "min": 0, "max": 20, "step": 1}),
|
|
"shadow_color": ("STRING", {"default": "purple"}),
|
|
"background_color": ("STRING", {"default": "black"}),
|
|
"rotation": ("FLOAT", {"default": 0.0, "min": 0.0, "max": 360.0, "step": 1.0}),
|
|
"spacing": ("FLOAT", {"default": 1.0, "min": 0.5, "max": 2.0, "step": 0.1}),
|
|
},
|
|
}
|
|
|
|
RETURN_TYPES = ("IMAGE",)
|
|
FUNCTION = "hexagonal_pattern"
|
|
CATEGORY = "🏵️Fill Nodes"
|
|
|
|
def t2p(self, t):
|
|
if t is not None:
|
|
i = 255.0 * t.cpu().numpy().squeeze()
|
|
p = Image.fromarray(np.clip(i, 0, 255).astype(np.uint8))
|
|
return p
|
|
|
|
def create_hexagon_mask(self, size):
|
|
mask = Image.new("L", (size, size), 0)
|
|
draw = ImageDraw.Draw(mask)
|
|
draw.regular_polygon((size // 2, size // 2, size // 2), 6, fill=255)
|
|
return mask
|
|
|
|
def process_input_value(self, value, index):
|
|
if isinstance(value, list):
|
|
if index >= len(value):
|
|
print(f"Warning: Value list index out of range. Using the last value.")
|
|
index = len(value) - 1
|
|
current_value = value[index]
|
|
index = (index + 1) % len(value)
|
|
else:
|
|
current_value = value
|
|
|
|
if hasattr(current_value, 'values'):
|
|
current_value = float(current_value.values[0])
|
|
|
|
return current_value, index
|
|
|
|
def hexagonal_pattern(self, images, hexagon_size=100, shadow_offset=5, shadow_color="black", shadow_opacity=0.5,
|
|
background_color="white", rotation=0.0, spacing=1.0):
|
|
out = []
|
|
total_images = len(images)
|
|
for i, img_tensor in enumerate(images, start=1):
|
|
p = self.t2p(img_tensor)
|
|
width, height = p.size
|
|
|
|
current_hexagon_size, self.hexagon_size_index = self.process_input_value(hexagon_size, self.hexagon_size_index)
|
|
current_shadow_offset, self.shadow_offset_index = self.process_input_value(shadow_offset, self.shadow_offset_index)
|
|
current_shadow_color, self.shadow_color_index = self.process_input_value(shadow_color, self.shadow_color_index)
|
|
current_background_color, self.background_color_index = self.process_input_value(background_color, self.background_color_index)
|
|
current_rotation, self.rotation_index = self.process_input_value(rotation, self.rotation_index)
|
|
current_spacing, self.spacing_index = self.process_input_value(spacing, self.spacing_index)
|
|
|
|
hexagon_mask = self.create_hexagon_mask(current_hexagon_size)
|
|
|
|
output_image = Image.new("RGBA", (width, height), current_background_color)
|
|
|
|
for y in range(0, height, int(current_hexagon_size * current_spacing * math.sqrt(3) / 2)):
|
|
for x in range(0, width, int(current_hexagon_size * current_spacing)):
|
|
if y % (2 * int(current_hexagon_size * current_spacing * math.sqrt(3) / 2)) == int(current_hexagon_size * current_spacing * math.sqrt(3) / 2):
|
|
x += int(current_hexagon_size * current_spacing) // 2
|
|
|
|
cropped_hexagon = p.crop((x, y, x + current_hexagon_size, y + current_hexagon_size)).rotate(current_rotation, expand=True)
|
|
|
|
shadow = Image.new("RGBA", cropped_hexagon.size, (0, 0, 0, 0))
|
|
shadow_mask = hexagon_mask.copy().resize(cropped_hexagon.size)
|
|
shadow.paste(current_shadow_color, (current_shadow_offset, current_shadow_offset), shadow_mask)
|
|
shadow.putalpha(int(255 * shadow_opacity))
|
|
|
|
output_image.paste(shadow, (x + current_shadow_offset, y + current_shadow_offset), shadow_mask)
|
|
output_image.paste(cropped_hexagon, (x, y), shadow_mask)
|
|
|
|
o = np.array(output_image.convert("RGB")).astype(np.float32) / 255.0
|
|
o = torch.from_numpy(o).unsqueeze(0)
|
|
out.append(o)
|
|
|
|
# Print progress update
|
|
progress = i / total_images * 100
|
|
sys.stdout.write(f"\rProcessing images: {progress:.2f}%")
|
|
sys.stdout.flush()
|
|
|
|
# Print a new line after the progress update
|
|
print()
|
|
|
|
out = torch.cat(out, 0)
|
|
return (out,)
|