This commit is contained in:
justumen
2025-06-11 14:32:34 +02:00
parent 3480d8a4ce
commit f43bce3516
3 changed files with 88 additions and 19 deletions

View File

@@ -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.

View File

@@ -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 overlays 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:
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)

View File

@@ -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]