remove mask output from the DropShadow node, add OuterGlow node.

This commit is contained in:
chflame163
2024-01-18 17:32:07 +08:00
committed by GitHub
parent 4936f80b8f
commit 2649bbff11
15 changed files with 446 additions and 253 deletions
+30 -5
View File
@@ -2,18 +2,23 @@
A set of nodes for ComfyUI that generate image like Adobe Photoshop's Layer Style.
the Drop Shadow is first completed node, and follow-up work is in progress.
Currently completed Drop Shadow and OuterGlow nodes, and follow-up work is in progress.
[中文说明点这里](./README_CN.MD)
## Update
Remove the mask channel output from the DropShadow node; Add the OuterGlow node.
## Node Description
### Drop Shadow:
Generate shadow
![image](image/drop_shadow_node.png)
![image](image/drop_shadow_example.png)
Node options:
![image](image/drop_shadow_node.png)
* background_image<sup>1</sup>: The background image.
* layer_image<sup>1</sup>: Layer image for composite.
* layer_mask<sup>1</sup>: Mask for layer_image, shadows are generated according to their shape.
@@ -29,11 +34,31 @@ Node options:
<sup>1</sup> The layer_image, layer_mask and the background_image, These three items must be of the same size.
Output type:
* image:Completed image.
* shadow_mask:Shadow's mask.
* image
### OuterGlow:
Generate outer glow
![image](image/outer_glow_example.png)
Node options:
![image](image/outer_glow_node.png)
* background_image<sup>1</sup>: The background image.
* layer_image<sup>1</sup>: Layer image for composite.
* layer_mask<sup>1</sup>: Mask for layer_image, shadows are generated according to their shape.
* invert_mask: Whether to reverse the mask.
* blend_mode: Blending method of glow, there are **_normal, multply, screen, add, subtract, difference, darker_** and **_lighter_**.
* opacity: Opacity of Glow.
* grow: Glow expansion amplitude.
* blur:Gkow blur level.
* glow_color: Glow color, described in hexadecimal RGB format.
<sup>1</sup> The layer_image, layer_mask and the background_image, These three items must be of the same size.
输出:
* image
## Example workflow
![image](image/drop_shadow.png)
image Some JSON workflow files in the workflow directory, that is example for ComfyUI.
## How to install
+34 -8
View File
@@ -1,15 +1,20 @@
# ComfyUI Layer Style:
ComfyUI插件,通过一组节点实现仿照Adobe Photoshop的图层样式。
Drop Shadow是首个完成的节点,后续工作进行中。
当前已完成Drop Shadow和OuterGlow节点,后续工作进行中。
## 更新说明:
DropShadow节点去掉调试mask通道输出;添加OuterGlow节点。
## 节点说明:
### Drop Shadow:
### DropShadow:
生成阴影。
![image](image/drop_shadow_example.png)
节点选项说明:
![image](image/drop_shadow_node.png)
选项说明:
* background_image<sup>1</sup>: 背景图像。
* layer_image<sup>1</sup>: 用于合成的层图像。
* layer_mask<sup>1</sup>: 层图像的遮罩,阴影按此生成。
@@ -25,11 +30,32 @@ Drop Shadow
<sup>1</sup> background_image, layer_image, layer_mask这三项必须是相同的尺寸。
输出:
* image:完成的图像。
* shadow_mask:阴影的通道。
* image
### OuterGlow:
生成外发光。
![image](image/outer_glow_example.png)
节点选项说明:
![image](image/outer_glow_node.png)
* background_image<sup>1</sup>: 背景图像。
* layer_image<sup>1</sup>: 用于合成的层图像。
* layer_mask<sup>1</sup>: 层图像的遮罩,阴影按此生成。
* invert_mask: 是否反转遮罩。
* blend_mode: 外发光的混合方式,包括normal、multply、screen、add、subtract、difference、darker和lighter。
* opacity: 外发光的不透明度。
* grow: 外发光扩张幅度。
* blur:外发光模糊程度。
* glow_color: 外发光颜色,使用16进制RGB格式描述。
<sup>1</sup> background_image, layer_image, layer_mask这三项必须是相同的尺寸。
输出:
* image
## 使用示例:
![image](image/drop_shadow.png)
在workflow目录下有json格式的工作流示例文件。
## 安装方法:
Binary file not shown.

After

Width:  |  Height:  |  Size: 442 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 70 KiB

After

Width:  |  Height:  |  Size: 100 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 419 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 90 KiB

Binary file not shown.
Binary file not shown.
Binary file not shown.
+7 -5
View File
@@ -23,12 +23,13 @@ class DropShadow:
"shadow_color": ("STRING", {"default": "#000000"}), # 背景颜色
},
"optional": {
# "test_mask": ("MASK",), #
}
}
RETURN_TYPES = ("IMAGE", "MASK",)
RETURN_NAMES = ("image", "shadow_mask",)
# RETURN_TYPES = ("IMAGE", "MASK",)
# RETURN_NAMES = ("image", "shadow_mask",)
RETURN_TYPES = ("IMAGE",)
RETURN_NAMES = ("image",)
FUNCTION = 'drop_shadow'
CATEGORY = '😺dzNodes'
OUTPUT_NODE = True
@@ -61,12 +62,13 @@ class DropShadow:
ret_image = _canvas
ret_mask = shadow_mask
return (pil2tensor(ret_image), ret_mask,)
# return (pil2tensor(ret_image), ret_mask,)
return (pil2tensor(ret_image),)
NODE_CLASS_MAPPINGS = {
"LayerStyle_DropShadow": DropShadow
}
NODE_DISPLAY_NAME_MAPPINGS = {
"LayerStyle_DropShadow": "Layer Style: Drop Shadow"
"LayerStyle_DropShadow": "LayerStyle: DropShadow"
}
+69
View File
@@ -0,0 +1,69 @@
from .imagefunc import *
class OuterGlow:
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",), #
"layer_mask": ("MASK",), #
"invert_mask": ("BOOLEAN", {"default": True}), # 反转mask
"blend_mode": (chop_mode,), # 混合模式
"opacity": ("INT", {"default": 100, "min": 0, "max": 100, "step": 1}), # 透明度
"grow": ("INT", {"default": 16, "min": -9999, "max": 9999, "step": 1}), # 扩张
"blur": ("INT", {"default": 20, "min": 0, "max": 100, "step": 1}), # 模糊
"glow_color": ("STRING", {"default": "#FFFFFF"}), # 背景颜色
},
"optional": {
}
}
# RETURN_TYPES = ("IMAGE", "MASK",)
# RETURN_NAMES = ("image", "glow_mask",)
RETURN_TYPES = ("IMAGE",)
RETURN_NAMES = ("image",)
FUNCTION = 'outer_glow'
CATEGORY = '😺dzNodes'
OUTPUT_NODE = True
def outer_glow(self, background_image, layer_image, layer_mask,
invert_mask, blend_mode, opacity,
grow, blur, glow_color,
):
# 处理mask
if invert_mask:
layer_mask = 1 - layer_mask
_layer = tensor2pil(layer_image)
_mask = mask2image(layer_mask)
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)
ret_image = _canvas
ret_mask = glow_mask
# return (pil2tensor(ret_image), ret_mask,)
return (pil2tensor(ret_image),)
NODE_CLASS_MAPPINGS = {
"LayerStyle_OuterGlow": OuterGlow
}
NODE_DISPLAY_NAME_MAPPINGS = {
"LayerStyle_OuterGlow": "LayerStyle: OuterGlow"
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 127 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

+101 -235
View File
@@ -1,13 +1,95 @@
{
"last_node_id": 20,
"last_link_id": 49,
"last_node_id": 23,
"last_link_id": 58,
"nodes": [
{
"id": 22,
"type": "LayerStyle_DropShadow",
"pos": [
540,
-660
],
"size": {
"0": 315,
"1": 266
},
"flags": {},
"order": 2,
"mode": 0,
"inputs": [
{
"name": "background_image",
"type": "IMAGE",
"link": 54
},
{
"name": "layer_image",
"type": "IMAGE",
"link": 55
},
{
"name": "layer_mask",
"type": "MASK",
"link": 56
}
],
"outputs": [
{
"name": "image",
"type": "IMAGE",
"links": [
58
],
"shape": 3,
"slot_index": 0
}
],
"properties": {
"Node name for S&R": "LayerStyle_DropShadow"
},
"widgets_values": [
true,
"normal",
50,
5,
5,
2,
15,
"#000000"
]
},
{
"id": 23,
"type": "SaveImage",
"pos": [
890,
-660
],
"size": [
315,
270
],
"flags": {},
"order": 3,
"mode": 0,
"inputs": [
{
"name": "images",
"type": "IMAGE",
"link": 58
}
],
"properties": {},
"widgets_values": [
"ComfyUI"
]
},
{
"id": 2,
"type": "LoadImage",
"pos": [
237,
-31
180,
-680
],
"size": {
"0": 315,
@@ -21,7 +103,7 @@
"name": "IMAGE",
"type": "IMAGE",
"links": [
45
55
],
"shape": 3,
"slot_index": 0
@@ -30,7 +112,7 @@
"name": "MASK",
"type": "MASK",
"links": [
46
56
],
"shape": 3,
"slot_index": 1
@@ -44,157 +126,26 @@
"image"
]
},
{
"id": 17,
"type": "RGB_Picker",
"pos": [
332,
-180
],
"size": {
"0": 210,
"1": 94
},
"flags": {},
"order": 1,
"mode": 0,
"outputs": [
{
"name": "value",
"type": "STRING",
"links": [
49
],
"shape": 3,
"slot_index": 0
}
],
"properties": {
"Node name for S&R": "RGB_Picker"
},
"widgets_values": [
"#2b0303",
"HEX"
]
},
{
"id": 9,
"type": "PreviewImage",
"pos": [
955,
-13
],
"size": {
"0": 210,
"1": 246
},
"flags": {},
"order": 4,
"mode": 0,
"inputs": [
{
"name": "images",
"type": "IMAGE",
"link": 47
}
],
"properties": {
"Node name for S&R": "PreviewImage"
}
},
{
"id": 20,
"type": "LayerStyle_DropShadow",
"pos": [
576,
-21
],
"size": [
355.20001220703125,
266
],
"flags": {},
"order": 3,
"mode": 0,
"inputs": [
{
"name": "background_image",
"type": "IMAGE",
"link": 44
},
{
"name": "layer_image",
"type": "IMAGE",
"link": 45
},
{
"name": "layer_mask",
"type": "MASK",
"link": 46
},
{
"name": "shadow_color",
"type": "STRING",
"link": 49,
"widget": {
"name": "shadow_color"
}
}
],
"outputs": [
{
"name": "image",
"type": "IMAGE",
"links": [
47
],
"shape": 3,
"slot_index": 0
},
{
"name": "shadow_mask",
"type": "MASK",
"links": [
48
],
"shape": 3,
"slot_index": 1
}
],
"properties": {
"Node name for S&R": "LayerStyle_DropShadow"
},
"widgets_values": [
true,
"multply",
52,
43,
45,
2,
20,
"#000000"
]
},
{
"id": 3,
"type": "LoadImage",
"pos": [
-102,
-33
-160,
-680
],
"size": {
"0": 315,
"1": 314
},
"flags": {},
"order": 2,
"order": 1,
"mode": 0,
"outputs": [
{
"name": "IMAGE",
"type": "IMAGE",
"links": [
44
54
],
"shape": 3,
"slot_index": 0
@@ -213,125 +164,40 @@
"512x512bkgd.jpg",
"image"
]
},
{
"id": 10,
"type": "MaskToImage",
"pos": [
957,
282
],
"size": {
"0": 210,
"1": 26
},
"flags": {},
"order": 5,
"mode": 0,
"inputs": [
{
"name": "mask",
"type": "MASK",
"link": 48
}
],
"outputs": [
{
"name": "IMAGE",
"type": "IMAGE",
"links": [
11
],
"shape": 3,
"slot_index": 0
}
],
"properties": {
"Node name for S&R": "MaskToImage"
}
},
{
"id": 11,
"type": "PreviewImage",
"pos": [
1188,
-15
],
"size": {
"0": 210,
"1": 246
},
"flags": {},
"order": 6,
"mode": 0,
"inputs": [
{
"name": "images",
"type": "IMAGE",
"link": 11
}
],
"properties": {
"Node name for S&R": "PreviewImage"
}
}
],
"links": [
[
11,
10,
0,
11,
0,
"IMAGE"
],
[
44,
54,
3,
0,
20,
22,
0,
"IMAGE"
],
[
45,
55,
2,
0,
20,
22,
1,
"IMAGE"
],
[
46,
56,
2,
1,
20,
22,
2,
"MASK"
],
[
47,
20,
58,
22,
0,
9,
23,
0,
"IMAGE"
],
[
48,
20,
1,
10,
0,
"MASK"
],
[
49,
17,
0,
20,
3,
"STRING"
]
],
"groups": [],
+205
View File
@@ -0,0 +1,205 @@
{
"last_node_id": 24,
"last_link_id": 62,
"nodes": [
{
"id": 23,
"type": "SaveImage",
"pos": [
890,
-660
],
"size": [
315,
270
],
"flags": {},
"order": 3,
"mode": 0,
"inputs": [
{
"name": "images",
"type": "IMAGE",
"link": 62
}
],
"properties": {},
"widgets_values": [
"ComfyUI"
]
},
{
"id": 3,
"type": "LoadImage",
"pos": [
-160,
-680
],
"size": {
"0": 315,
"1": 314
},
"flags": {},
"order": 0,
"mode": 0,
"outputs": [
{
"name": "IMAGE",
"type": "IMAGE",
"links": [
59
],
"shape": 3,
"slot_index": 0
},
{
"name": "MASK",
"type": "MASK",
"links": null,
"shape": 3
}
],
"properties": {
"Node name for S&R": "LoadImage"
},
"widgets_values": [
"512x512bkgd.jpg",
"image"
]
},
{
"id": 2,
"type": "LoadImage",
"pos": [
180,
-680
],
"size": {
"0": 315,
"1": 314
},
"flags": {},
"order": 1,
"mode": 0,
"outputs": [
{
"name": "IMAGE",
"type": "IMAGE",
"links": [
60
],
"shape": 3,
"slot_index": 0
},
{
"name": "MASK",
"type": "MASK",
"links": [
61
],
"shape": 3,
"slot_index": 1
}
],
"properties": {
"Node name for S&R": "LoadImage"
},
"widgets_values": [
"512x512.png",
"image"
]
},
{
"id": 24,
"type": "LayerStyle_OuterGlow",
"pos": [
536,
-631
],
"size": {
"0": 315,
"1": 218
},
"flags": {},
"order": 2,
"mode": 0,
"inputs": [
{
"name": "background_image",
"type": "IMAGE",
"link": 59
},
{
"name": "layer_image",
"type": "IMAGE",
"link": 60
},
{
"name": "layer_mask",
"type": "MASK",
"link": 61
}
],
"outputs": [
{
"name": "image",
"type": "IMAGE",
"links": [
62
],
"shape": 3,
"slot_index": 0
}
],
"properties": {
"Node name for S&R": "LayerStyle_OuterGlow"
},
"widgets_values": [
true,
"normal",
100,
16,
20,
"#FFFFFF"
]
}
],
"links": [
[
59,
3,
0,
24,
0,
"IMAGE"
],
[
60,
2,
0,
24,
1,
"IMAGE"
],
[
61,
2,
1,
24,
2,
"MASK"
],
[
62,
24,
0,
23,
0,
"IMAGE"
]
],
"groups": [],
"config": {},
"extra": {},
"version": 0.4
}