mirror of
https://github.com/justUmen/Bjornulf_custom_nodes.git
synced 2026-03-21 12:42:11 -03:00
v1.1.8
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
# 🔗 Comfyui : Bjornulf_custom_nodes v1.1.7 🔗
|
||||
# 🔗 Comfyui : Bjornulf_custom_nodes v1.1.8 🔗
|
||||
|
||||
A list of 170 custom nodes for Comfyui : Display, manipulate, create and edit text, images, videos, loras, generate characters and more.
|
||||
You can manage looping operations, generate randomized content, trigger logical conditions, pause and manually control your workflows and even work with external AI tools, like Ollama or Text To Speech.
|
||||
|
||||
@@ -17,12 +17,14 @@ class CombineBackgroundOverlay:
|
||||
},
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("IMAGE",)
|
||||
RETURN_TYPES = ("IMAGE", "MASK")
|
||||
RETURN_NAMES = ("image", "mask")
|
||||
FUNCTION = "combine_background_overlay"
|
||||
CATEGORY = "Bjornulf"
|
||||
|
||||
def combine_background_overlay(self, background, overlay, horizontal_position, vertical_position, mask=None):
|
||||
results = []
|
||||
output_masks = []
|
||||
|
||||
# Process the first background image
|
||||
bg = background[0].cpu().numpy()
|
||||
@@ -45,7 +47,7 @@ class CombineBackgroundOverlay:
|
||||
else:
|
||||
ov_img = Image.fromarray(ov, 'RGB')
|
||||
|
||||
# Apply mask if provided
|
||||
# Apply mask if provided - INVERTED LOGIC: mask removes opacity
|
||||
if mask is not None:
|
||||
mask_idx = min(i, mask.shape[0] - 1)
|
||||
m = mask[mask_idx].cpu().numpy()
|
||||
@@ -56,15 +58,18 @@ class CombineBackgroundOverlay:
|
||||
if mask_img.size != ov_img.size:
|
||||
mask_img = mask_img.resize(ov_img.size, Image.LANCZOS)
|
||||
|
||||
# INVERT THE MASK - white areas in mask become transparent
|
||||
inverted_mask = Image.eval(mask_img, lambda x: 255 - x)
|
||||
|
||||
if ov_img.mode == 'RGBA':
|
||||
# Combine overlay’s alpha with mask
|
||||
# Combine overlay's alpha with inverted mask
|
||||
ov_alpha = np.array(ov_img.split()[3], dtype=np.float32) / 255.0
|
||||
mask_alpha = np.array(mask_img, dtype=np.float32) / 255.0
|
||||
effective_alpha = (ov_alpha * mask_alpha * 255).astype(np.uint8)
|
||||
inverted_mask_alpha = np.array(inverted_mask, dtype=np.float32) / 255.0
|
||||
effective_alpha = (ov_alpha * inverted_mask_alpha * 255).astype(np.uint8)
|
||||
ov_img.putalpha(Image.fromarray(effective_alpha, 'L'))
|
||||
else:
|
||||
# Use mask as alpha for RGB overlay
|
||||
ov_img.putalpha(mask_img)
|
||||
# Use inverted mask as alpha for RGB overlay
|
||||
ov_img.putalpha(inverted_mask)
|
||||
else:
|
||||
if ov_img.mode == 'RGB':
|
||||
# Add fully opaque alpha for RGB overlay
|
||||
@@ -82,26 +87,90 @@ class CombineBackgroundOverlay:
|
||||
result = Image.new('RGBA', bg_img.size, (0, 0, 0, 0))
|
||||
result.paste(bg_img, (0, 0))
|
||||
|
||||
# Paste overlay with alpha blending
|
||||
# Create output mask - start with background alpha or white
|
||||
if bg_has_alpha:
|
||||
output_mask_img = bg_img.split()[3].copy()
|
||||
else:
|
||||
output_mask_img = Image.new('L', bg_img.size, 255)
|
||||
|
||||
# Paste overlay directly on top (no alpha blending)
|
||||
if x + ov_img.width > 0 and y + ov_img.height > 0 and x < result.width and y < result.height:
|
||||
temp = Image.new('RGBA', result.size, (0, 0, 0, 0))
|
||||
temp.paste(ov_img, (x, y), ov_img)
|
||||
result = Image.alpha_composite(result.convert('RGBA'), temp)
|
||||
# Convert overlay to RGB if needed for direct paste
|
||||
if ov_img.mode == 'RGBA':
|
||||
ov_rgb = Image.new('RGB', ov_img.size, (255, 255, 255))
|
||||
ov_rgb.paste(ov_img, mask=ov_img.split()[3])
|
||||
ov_paste = ov_rgb
|
||||
paste_mask = ov_img.split()[3]
|
||||
else:
|
||||
ov_paste = ov_img
|
||||
paste_mask = None
|
||||
|
||||
# Apply input mask if provided - UPDATED LOGIC FOR INVERTED MASK
|
||||
if mask is not None:
|
||||
mask_idx = min(i, mask.shape[0] - 1)
|
||||
m = mask[mask_idx].cpu().numpy()
|
||||
m = np.clip(m * 255, 0, 255).astype(np.uint8)
|
||||
input_mask = Image.fromarray(m, 'L')
|
||||
if input_mask.size != ov_img.size:
|
||||
input_mask = input_mask.resize(ov_img.size, Image.LANCZOS)
|
||||
|
||||
# INVERT THE INPUT MASK
|
||||
inverted_input_mask = Image.eval(input_mask, lambda x: 255 - x)
|
||||
|
||||
if paste_mask is not None:
|
||||
# Combine overlay alpha with inverted input mask
|
||||
paste_mask_array = np.array(paste_mask, dtype=np.float32) / 255.0
|
||||
inverted_input_mask_array = np.array(inverted_input_mask, dtype=np.float32) / 255.0
|
||||
combined_mask_array = (paste_mask_array * inverted_input_mask_array * 255).astype(np.uint8)
|
||||
paste_mask = Image.fromarray(combined_mask_array, 'L')
|
||||
else:
|
||||
# Use inverted input mask directly
|
||||
paste_mask = inverted_input_mask
|
||||
|
||||
# Paste overlay directly onto result
|
||||
result.paste(ov_paste, (x, y), paste_mask)
|
||||
|
||||
# Update output mask
|
||||
if paste_mask is not None:
|
||||
temp_mask = Image.new('L', result.size, 0)
|
||||
temp_mask.paste(paste_mask, (x, y))
|
||||
|
||||
# Combine masks - overlay mask replaces background mask where it exists
|
||||
output_mask_array = np.array(output_mask_img, dtype=np.float32)
|
||||
temp_mask_array = np.array(temp_mask, dtype=np.float32)
|
||||
combined_mask_array = np.maximum(output_mask_array, temp_mask_array).astype(np.uint8)
|
||||
output_mask_img = Image.fromarray(combined_mask_array, 'L')
|
||||
else:
|
||||
# No mask - overlay covers background completely in paste area
|
||||
temp_mask = Image.new('L', result.size, 0)
|
||||
temp_mask.paste(Image.new('L', ov_paste.size, 255), (x, y))
|
||||
|
||||
output_mask_array = np.array(output_mask_img, dtype=np.float32)
|
||||
temp_mask_array = np.array(temp_mask, dtype=np.float32)
|
||||
combined_mask_array = np.maximum(output_mask_array, temp_mask_array).astype(np.uint8)
|
||||
output_mask_img = Image.fromarray(combined_mask_array, 'L')
|
||||
|
||||
# Convert result back to tensor
|
||||
result_np = np.array(result)
|
||||
if bg_has_alpha:
|
||||
result_tensor = torch.from_numpy(result_np).float() / 255.0
|
||||
else:
|
||||
# Convert RGBA to RGB, blending with white only where needed
|
||||
if result_np.shape[2] == 4:
|
||||
# Convert RGBA back to RGB if background was RGB
|
||||
if not bg_has_alpha:
|
||||
alpha = result_np[:, :, 3:4] / 255.0
|
||||
rgb = result_np[:, :, :3]
|
||||
white_bg = np.ones_like(rgb) * 255
|
||||
result_np = (rgb * alpha + white_bg * (1 - alpha)).astype(np.uint8)
|
||||
result_tensor = torch.from_numpy(result_np).float() / 255.0
|
||||
else:
|
||||
result_tensor = torch.from_numpy(result_np).float() / 255.0
|
||||
else:
|
||||
result_tensor = torch.from_numpy(result_np).float() / 255.0
|
||||
|
||||
# Convert output mask to tensor
|
||||
output_mask_tensor = torch.from_numpy(np.array(output_mask_img)).float() / 255.0
|
||||
|
||||
results.append(result_tensor)
|
||||
output_masks.append(output_mask_tensor)
|
||||
|
||||
final_result = torch.stack(results)
|
||||
return (final_result,)
|
||||
final_masks = torch.stack(output_masks)
|
||||
return (final_result, final_masks)
|
||||
@@ -1,7 +1,7 @@
|
||||
[project]
|
||||
name = "bjornulf_custom_nodes"
|
||||
description = "170 ComfyUI nodes : Display, manipulate, and edit text, images, videos, loras, generate characters and more. Manage looping operations, generate randomized content, use logical conditions and work with external AI tools, like Ollama or Text To Speech, etc..."
|
||||
version = "1.1.7"
|
||||
version = "1.1.8"
|
||||
license = {file = "LICENSE"}
|
||||
|
||||
[project.urls]
|
||||
|
||||
Reference in New Issue
Block a user