layer_mask is not a mandatory input
This commit is contained in:
@@ -7,6 +7,8 @@ Currently completed Drop Shadow and OuterGlow nodes, and follow-up work is in pr
|
||||
[中文说明点这里](./README_CN.MD)
|
||||
|
||||
## Update
|
||||
* Now, layer_mask is not a mandatory input. without inputting will use the layer_image's alpha channel. It is allowed to use layers and masks with different shapes, but the size must be consistent.
|
||||

|
||||
* Commit ImageBlend node.
|
||||
* Remove the mask channel output from the DropShadow node; Commit OuterGlow node.
|
||||
* Commit DropShadow node.
|
||||
|
||||
@@ -3,6 +3,8 @@ ComfyUI
|
||||
当前已完成Drop Shadow和OuterGlow节点,后续工作进行中。
|
||||
|
||||
## 更新说明:
|
||||
* 现在layer_mask不是输入必选。不输入将使用layer_image的alpha通道。允许使用形状不同的layer和mask,但是尺寸必须一致。
|
||||

|
||||
* 添加ImageBlend节点
|
||||
* DropShadow节点去掉调试mask通道输出;添加OuterGlow节点。
|
||||
* DropShadow节点上线。
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+17
-14
@@ -12,7 +12,6 @@ class DropShadow:
|
||||
"required": {
|
||||
"background_image": ("IMAGE", ), #
|
||||
"layer_image": ("IMAGE",), #
|
||||
"layer_mask": ("MASK",), #
|
||||
"invert_mask": ("BOOLEAN", {"default": True}), # 反转mask
|
||||
"blend_mode": (chop_mode,), # 混合模式
|
||||
"opacity": ("INT", {"default": 50, "min": 0, "max": 100, "step": 1}), # 透明度
|
||||
@@ -23,6 +22,7 @@ class DropShadow:
|
||||
"shadow_color": ("STRING", {"default": "#000000"}), # 背景颜色
|
||||
},
|
||||
"optional": {
|
||||
"layer_mask": ("MASK",), #
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,34 +34,37 @@ class DropShadow:
|
||||
CATEGORY = '😺dzNodes'
|
||||
OUTPUT_NODE = True
|
||||
|
||||
def drop_shadow(self, background_image, layer_image, layer_mask,
|
||||
def drop_shadow(self, background_image, layer_image,
|
||||
invert_mask, blend_mode, opacity, distance_x, distance_y,
|
||||
grow, blur, shadow_color,
|
||||
layer_mask=None,
|
||||
):
|
||||
distance_x = -distance_x
|
||||
distance_y = -distance_y
|
||||
# 处理阴影mask
|
||||
if invert_mask:
|
||||
layer_mask = 1 - layer_mask
|
||||
_layer = tensor2pil(layer_image)
|
||||
_mask = mask2image(layer_mask)
|
||||
_canvas = tensor2pil(background_image).convert('RGB')
|
||||
_layer = tensor2pil(layer_image).convert('RGB')
|
||||
_mask = tensor2pil(layer_image).convert('RGBA').split()[-1]
|
||||
# 处理mask
|
||||
if layer_mask is not None:
|
||||
if invert_mask:
|
||||
layer_mask = 1 - layer_mask
|
||||
_mask = mask2image(layer_mask).convert('L')
|
||||
|
||||
if distance_x != 0 or distance_y != 0:
|
||||
_mask = shift_image(_mask, distance_x, distance_y) # 位移
|
||||
shadow_mask = expand_mask(image2mask(_mask), grow, blur, 0) #扩张,模糊
|
||||
__mask = shift_image(_mask, distance_x, distance_y) # 位移
|
||||
shadow_mask = expand_mask(image2mask(__mask), grow, blur, 0) #扩张,模糊
|
||||
|
||||
# 合成阴影
|
||||
shadow_color = Image.new("RGB", _layer.size, color=shadow_color)
|
||||
alpha = tensor2pil(shadow_mask).convert('L')
|
||||
_canvas = tensor2pil(background_image)
|
||||
_shadow = chop_image(tensor2pil(background_image), shadow_color, blend_mode, opacity)
|
||||
_shadow = chop_image(_canvas, shadow_color, blend_mode, opacity)
|
||||
_canvas.paste(_shadow, mask=alpha)
|
||||
|
||||
# 合成layer
|
||||
alpha = tensor2pil(layer_mask).convert('L')
|
||||
_canvas.paste(_layer, mask=alpha)
|
||||
_canvas.paste(_layer, mask=_mask)
|
||||
|
||||
ret_image = _canvas
|
||||
ret_mask = shadow_mask
|
||||
# ret_mask = shadow_mask
|
||||
# return (pil2tensor(ret_image), ret_mask,)
|
||||
return (pil2tensor(ret_image),)
|
||||
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
from .imagefunc import *
|
||||
|
||||
class ImageBlend:
|
||||
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
@classmethod
|
||||
def INPUT_TYPES(self):
|
||||
chop_mode = ['normal','multply','screen','add','subtract','difference','darker','lighter']
|
||||
return {
|
||||
"required": {
|
||||
"background_image": ("IMAGE", ), #
|
||||
"layer_image": ("IMAGE",), #
|
||||
|
||||
"invert_mask": ("BOOLEAN", {"default": True}), # 反转mask
|
||||
"blend_mode": (chop_mode,), # 混合模式
|
||||
"opacity": ("INT", {"default": 100, "min": 0, "max": 100, "step": 1}), # 透明度
|
||||
},
|
||||
"optional": {
|
||||
"layer_mask": ("MASK",), #
|
||||
}
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("IMAGE",)
|
||||
RETURN_NAMES = ("image",)
|
||||
FUNCTION = 'image_blend'
|
||||
CATEGORY = '😺dzNodes'
|
||||
OUTPUT_NODE = True
|
||||
|
||||
def image_blend(self, background_image, layer_image,
|
||||
invert_mask, blend_mode, opacity,
|
||||
layer_mask=None,
|
||||
):
|
||||
|
||||
_canvas = tensor2pil(background_image).convert('RGB')
|
||||
_layer = tensor2pil(layer_image).convert('RGB')
|
||||
_mask = tensor2pil(layer_image).convert('RGBA').split()[-1]
|
||||
if layer_mask is not None:
|
||||
if invert_mask:
|
||||
layer_mask = 1 - layer_mask
|
||||
_mask = mask2image(layer_mask).convert('L')
|
||||
|
||||
# 合成layer
|
||||
_comp = chop_image(_canvas, _layer, blend_mode, opacity)
|
||||
|
||||
_canvas.paste(_comp, mask=_mask)
|
||||
|
||||
|
||||
ret_image = _canvas
|
||||
return (pil2tensor(ret_image),)
|
||||
|
||||
NODE_CLASS_MAPPINGS = {
|
||||
"LayerStyle_ImageBlend": ImageBlend
|
||||
}
|
||||
|
||||
NODE_DISPLAY_NAME_MAPPINGS = {
|
||||
"LayerStyle_ImageBlend": "LayerStyle: ImageBlend"
|
||||
}
|
||||
@@ -35,7 +35,6 @@ def image2mask(image:Image) -> torch.Tensor:
|
||||
|
||||
def mask2image(mask:torch.Tensor) -> Image:
|
||||
masks = tensor2np(mask)
|
||||
# images = []
|
||||
for m in masks:
|
||||
_mask = Image.fromarray(m).convert("L")
|
||||
_image = Image.new("RGBA", _mask.size, color='white')
|
||||
|
||||
+13
-10
@@ -12,7 +12,6 @@ class OuterGlow:
|
||||
"required": {
|
||||
"background_image": ("IMAGE", ), #
|
||||
"layer_image": ("IMAGE",), #
|
||||
"layer_mask": ("MASK",), #
|
||||
"invert_mask": ("BOOLEAN", {"default": True}), # 反转mask
|
||||
"blend_mode": (chop_mode,), # 混合模式
|
||||
"opacity": ("INT", {"default": 100, "min": 0, "max": 100, "step": 1}), # 透明度
|
||||
@@ -21,6 +20,7 @@ class OuterGlow:
|
||||
"glow_color": ("STRING", {"default": "#FFFFFF"}), # 背景颜色
|
||||
},
|
||||
"optional": {
|
||||
"layer_mask": ("MASK",), #
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,31 +32,34 @@ class OuterGlow:
|
||||
CATEGORY = '😺dzNodes'
|
||||
OUTPUT_NODE = True
|
||||
|
||||
def outer_glow(self, background_image, layer_image, layer_mask,
|
||||
def outer_glow(self, background_image, layer_image,
|
||||
invert_mask, blend_mode, opacity,
|
||||
grow, blur, glow_color,
|
||||
layer_mask=None,
|
||||
):
|
||||
|
||||
_canvas = tensor2pil(background_image).convert('RGB')
|
||||
_layer = tensor2pil(layer_image).convert('RGB')
|
||||
_mask = tensor2pil(layer_image).convert('RGBA').split()[-1]
|
||||
# 处理mask
|
||||
if invert_mask:
|
||||
layer_mask = 1 - layer_mask
|
||||
_layer = tensor2pil(layer_image)
|
||||
_mask = mask2image(layer_mask)
|
||||
if layer_mask is not None:
|
||||
if invert_mask:
|
||||
layer_mask = 1 - layer_mask
|
||||
_mask = mask2image(layer_mask).convert('L')
|
||||
|
||||
glow_mask = expand_mask(image2mask(_mask), grow, blur, 0) #扩张,模糊
|
||||
|
||||
# 合成glow
|
||||
glow_color = Image.new("RGB", _layer.size, color=glow_color)
|
||||
alpha = tensor2pil(glow_mask).convert('L')
|
||||
_canvas = tensor2pil(background_image)
|
||||
_glow = chop_image(tensor2pil(background_image), glow_color, blend_mode, opacity)
|
||||
_canvas.paste(_glow, mask=alpha)
|
||||
|
||||
# 合成layer
|
||||
alpha = tensor2pil(layer_mask).convert('L')
|
||||
_canvas.paste(_layer, mask=alpha)
|
||||
_canvas.paste(_layer, mask=_mask)
|
||||
|
||||
ret_image = _canvas
|
||||
ret_mask = glow_mask
|
||||
# ret_mask = glow_mask
|
||||
# return (pil2tensor(ret_image), ret_mask,)
|
||||
return (pil2tensor(ret_image),)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user