upgrade OuterGlow node

This commit is contained in:
chflame163
2024-01-20 10:39:05 +08:00
committed by GitHub
parent 5f64f4cb22
commit 61e75a6e31
14 changed files with 362 additions and 242 deletions
+10 -6
View File
@@ -6,6 +6,7 @@ Currently completed the Drop Shadow, OuterGlow, and some auxiliary nodes. follow
[中文说明点这里](./README_CN.MD)
## Update
* OuterGlow node has undergone significant modifications by adding options for **_brightness_**, **_light_color_**, and **_glow_color_**. workflows containing old version nodes need to be manually replaced with new version nodes.
* Commit MaskInvert node.
* Commit ColorPick node.
* Commit Stroke node.
@@ -35,7 +36,7 @@ Node options:
* distance_y: Vertical offset of shadow.
* grow: Shadow expansion amplitude.
* blur: Shadow blur level.
* shadow_color: Shadow color, described in hexadecimal RGB format.
* shadow_color<sup>4</sup>: Shadow color.
Output type:
* image
@@ -53,9 +54,11 @@ Node options:
* invert_mask: Whether to reverse the mask.
* blend_mode<sup>3</sup>: Blending mode of glow.
* opacity: Opacity of glow.
* grow: Glow expansion amplitude.
* blur: Gkow blur level.
* glow_color: Glow color, described in hexadecimal RGB format.
* brightness: Luminance of light.
* glow_range: range of glow.
* blur:blur of glow.
* light_color<sup>4</sup>: Light color.
* glow_color<sup>4</sup>: Edge part color of glow.
Output type:
@@ -75,7 +78,7 @@ Node options:
* opacity: Opacity of stroke.
* inner_stroke<sup>*</sup>: Stroke shrinkage amplitude.
* outer_stroke<sup>*</sup>: Stroke expansion amplitude.
* stroke_color: Stroke color, described in hexadecimal RGB format.
* stroke_color<sup>4</sup>: Stroke color, described in hexadecimal RGB format.
<sup>*</sup>The width of the stroke is equal to inner_stroke plus outer_stroke value. Setting two values separately can make it more convenient to adjust the border range.
@@ -147,6 +150,8 @@ Output Type:
<sup>3</sup> The blend mode include **_normal, multply, screen, add, subtract, difference, darker_** and **_lighter_**.
<sup>4</sup> The RGB color described by hexadecimal RGB format, like '#FA3D86'.
## Example workflow
image Some JSON workflow files in the workflow directory, that is example for ComfyUI.
@@ -159,7 +164,6 @@ image Some JSON workflow files in the workflow directory, that is example for Co
* Gradient Overlay
## How to install
* Open the cmd window in the plugin directory of ComfyUI, like "ComfyUI\custom_nodes\",type```git clone https://github.com/chflame163/ComfyUI_LayerStyle.git```
+9 -7
View File
@@ -4,6 +4,7 @@ ComfyUI
当前已完成Drop Shadow和OuterGlow节点和一些辅助节点,后续工作进行中。
## 更新说明:
* OuterGlow节点重大修改,增加亮度、灯光颜色、辉光颜色选项。包含旧版节点的工作流需手动替换新版节点。
* 添加MaskInvert节点。
* 添加Stroke节点。
* 添加MaskPreview节点。
@@ -32,7 +33,7 @@ ComfyUI
* distance_y: 阴影的垂直方向偏移量。
* grow: 阴影扩张幅度。
* blur:阴影模糊程度。
* shadow_color: 阴影颜色,使用16进制RGB格式描述。
* shadow_color<sup>4</sup>: 阴影颜色。
输出:
@@ -50,9 +51,11 @@ ComfyUI
* invert_mask: 是否反转遮罩。
* blend_mode<sup>3</sup>: 发光的混合模式。
* opacity: 发光的不透明度。
* grow: 发光扩张幅度。
* brightness: 发光亮度。
* glow_range: 发光范围。
* blur:发光模糊程度。
* glow_color: 发光颜色,使用16进制RGB格式描述。
* light_color<sup>4</sup>: 发光中心颜色。
* glow_colo<sup>4</sup>: 辉光外围颜色。
输出:
@@ -72,7 +75,7 @@ ComfyUI
* opacity: 不透明度。
* inner_stroke<sup>*</sup>: 描边向内收缩幅度。
* outer_stroke<sup>*</sup>:描边向外扩张幅度。
* stroke_color: 描边颜色,使用16进制RGB格式描述。
* stroke_color<sup>4</sup>: 描边颜色。
<sup>*</sup>描边的宽度等于收缩值加上扩张值。两个值分开设置能更方便的调整边框范围。
@@ -146,6 +149,7 @@ mask
<sup>1</sup> image、mask和background_image(如果有输入)这三项必须是相同的尺寸。
<sup>2</sup> mask不是必须的输入项,默认使用image的alpha通道,如果image输入不包含alpha通道将自动创建整个图像的alpha通道。如果输入mask,原本的alpha通道将被mask覆盖。
<sup>3</sup>: 混合模式包括normal、multply、screen、add、subtract、difference、darker和lighter。
<sup>4</sup>: 颜色使用16进制RGB字符串格式描述,例如 '#FA3D86'。
## 使用示例:
@@ -155,13 +159,11 @@ mask
* Inner Shadow
* Inner Glow
* Stroke
* Texture
* Color Overlay
* Gradient Overlay
*
## 安装方法:
* 在CompyUI插件目录(例如“CompyUI\custom_nodes\”)中打开cmd窗口,键入```git clone https://github.com/chflame163/ComfyUI_LayerStyle.git```安装。或者下载解压zip文件,将得到的文件夹复制到 ComfyUI\custom_nodes\
Binary file not shown.

Before

Width:  |  Height:  |  Size: 419 KiB

After

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 90 KiB

After

Width:  |  Height:  |  Size: 128 KiB

+5 -8
View File
@@ -1,13 +1,8 @@
from .imagefunc import Hex_to_RGB
mode_list = ['HEX', 'DEC']
def hex_to_dec(inhex):
rval = inhex[1:3]
gval = inhex[3:5]
bval = inhex[5:]
rgbval = (int(rval, 16), int(gval, 16), int(bval, 16))
return rgbval
class ColorPicker:
def __init__(self):
@@ -33,8 +28,10 @@ class ColorPicker:
def picker(self, color, mode,):
ret = color
if ret == 'white':
ret = "#FFFFFF"
if mode == 'DEC':
ret = hex_to_dec(color)
ret = Hex_to_RGB(ret)
return (ret,)
+1
View File
@@ -26,6 +26,7 @@ class DropShadow:
}
}
log('DropShadow Processing...')
# RETURN_TYPES = ("IMAGE", "MASK",)
# RETURN_NAMES = ("image", "shadow_mask",)
RETURN_TYPES = ("IMAGE",)
+1
View File
@@ -32,6 +32,7 @@ class ImageBlend:
layer_mask=None,
):
log('ImageBlend Processing...')
_canvas = tensor2pil(background_image).convert('RGB')
_layer = tensor2pil(layer_image).convert('RGB')
_mask = tensor2pil(layer_image).convert('RGBA').split()[-1]
+1
View File
@@ -19,6 +19,7 @@ class ImageOpacity:
}
}
log('ImageOpacity Processing...')
RETURN_TYPES = ("IMAGE", "MASK",)
RETURN_NAMES = ("image", "mask",)
FUNCTION = 'image_opacity'
+38
View File
@@ -135,3 +135,41 @@ def remove_background(image:Image, mask:Image, color:str) -> Image:
def subtract_mask(masks_a, masks_b):
return torch.clamp(masks_a - masks_b, 0, 255)
def RGB_to_Hex(RGB):
# _rgb = tuple(map(int, RGB[1:-1].split(',')))
_rgb = RGB
color = '#'
for i in _rgb:
num = int(i)
color += str(hex(num))[-2:].replace('x', '0').upper()
return color
def Hex_to_RGB(inhex):
rval = inhex[1:3]
gval = inhex[3:5]
bval = inhex[5:]
rgb = (int(rval, 16), int(gval, 16), int(bval, 16))
return tuple(rgb)
def step_value(start_value, end_value, total_step, step):
factor = step / total_step
return int((end_value - start_value) * factor) + start_value
def step_color(start_color, end_color, total_step, step):
if isinstance(start_color, str):
start_color = tuple(Hex_to_RGB(start_color))
if isinstance(end_color, str):
end_color = tuple(Hex_to_RGB(end_color))
start_R, start_G, start_B = start_color[0], start_color[1], start_color[2]
end_R, end_G, end_B = end_color[0], end_color[1], end_color[2]
ret_color = (step_value(start_R, end_R, total_step, step),
step_value(start_G, end_G, total_step, step),
step_value(start_B, end_B, total_step, step),
)
if isinstance(start_color, str):
return RGB_to_Hex(ret_color)
else:
return ret_color
+21 -16
View File
@@ -7,7 +7,7 @@ class OuterGlow:
@classmethod
def INPUT_TYPES(self):
chop_mode = ['normal','multply','screen','add','subtract','difference','darker','lighter']
chop_mode = ['screen', 'add', 'lighter', 'normal', 'multply', 'subtract','difference','darker']
return {
"required": {
"background_image": ("IMAGE", ), #
@@ -15,17 +15,17 @@ class OuterGlow:
"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"}), # 背景颜色
"brightness": ("INT", {"default": 5, "min": 2, "max": 20, "step": 1}), # 迭代
"glow_range": ("INT", {"default": 48, "min": -9999, "max": 9999, "step": 1}), # 扩张
"blur": ("INT", {"default": 25, "min": 0, "max": 9999, "step": 1}), # 扩张
"light_color": ("STRING", {"default": "#FFBF30"}), # 光源中心颜色
"glow_color": ("STRING", {"default": "#FE0000"}), # 辉光外围颜色
},
"optional": {
"layer_mask": ("MASK",), #
}
}
# RETURN_TYPES = ("IMAGE", "MASK",)
# RETURN_NAMES = ("image", "glow_mask",)
RETURN_TYPES = ("IMAGE",)
RETURN_NAMES = ("image",)
FUNCTION = 'outer_glow'
@@ -34,10 +34,11 @@ class OuterGlow:
def outer_glow(self, background_image, layer_image,
invert_mask, blend_mode, opacity,
grow, blur, glow_color,
brightness, glow_range, blur, light_color, glow_color,
layer_mask=None,
):
log('OuterGLow Advance Processing...')
_canvas = tensor2pil(background_image).convert('RGB')
_layer = tensor2pil(layer_image).convert('RGB')
_mask = tensor2pil(layer_image).convert('RGBA').split()[-1]
@@ -46,19 +47,23 @@ class OuterGlow:
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')
_glow = chop_image(tensor2pil(background_image), glow_color, blend_mode, opacity)
_canvas.paste(_glow, mask=alpha)
blur_factor = blur / 20.0
grow = glow_range
for x in range(brightness):
blur = int(grow * blur_factor)
_color = step_color(glow_color, light_color, brightness, x)
glow_mask = expand_mask(image2mask(_mask), grow, blur) #扩张,模糊
# 合成glow
color_image = Image.new("RGB", _layer.size, color=_color)
alpha = tensor2pil(glow_mask).convert('L')
_glow = chop_image(_canvas, color_image, blend_mode, step_value(1, opacity, brightness, x))
_canvas.paste(_glow, mask=alpha)
grow = grow - int(glow_range/brightness)
# 合成layer
_canvas.paste(_layer, mask=_mask)
ret_image = _canvas
# ret_mask = glow_mask
# return (pil2tensor(ret_image), ret_mask,)
return (pil2tensor(ret_image),)
NODE_CLASS_MAPPINGS = {
+1
View File
@@ -37,6 +37,7 @@ class Stroke:
layer_mask=None,
):
log('Stroke Processing...')
_canvas = tensor2pil(background_image).convert('RGB')
_layer = tensor2pil(layer_image).convert('RGB')
_mask = tensor2pil(layer_image).convert('RGBA').split()[-1]
+2 -1
View File
@@ -2,4 +2,5 @@ numpy
pillow
torch
matplotlib
Scipy
Scipy
opencv-python
Binary file not shown.

After

Width:  |  Height:  |  Size: 382 KiB

+273 -204
View File
@@ -1,205 +1,274 @@
{
"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
{
"last_node_id": 5,
"last_link_id": 4,
"nodes": [
{
"id": 1,
"type": "LoadImage",
"pos": [
279,
378
],
"size": {
"0": 279.00006103515625,
"1": 314
},
"flags": {},
"order": 0,
"mode": 0,
"outputs": [
{
"name": "IMAGE",
"type": "IMAGE",
"links": [
1,
2
],
"shape": 3,
"slot_index": 0
},
{
"name": "MASK",
"type": "MASK",
"links": null,
"shape": 3
}
],
"properties": {
"Node name for S&R": "LoadImage"
},
"widgets_values": [
"D04QPvc (7).jpg",
"image"
]
},
{
"id": 2,
"type": "Image Remove Background Rembg (mtb)",
"pos": [
597,
405
],
"size": {
"0": 294,
"1": 230
},
"flags": {},
"order": 2,
"mode": 0,
"inputs": [
{
"name": "image",
"type": "IMAGE",
"link": 1
}
],
"outputs": [
{
"name": "Image (rgba)",
"type": "IMAGE",
"links": [
3
],
"shape": 3,
"slot_index": 0
},
{
"name": "Mask",
"type": "MASK",
"links": null,
"shape": 3
},
{
"name": "Image",
"type": "IMAGE",
"links": null,
"shape": 3
}
],
"properties": {
"Node name for S&R": "Image Remove Background Rembg (mtb)"
},
"widgets_values": [
false,
240,
10,
10,
false,
"#000000"
]
},
{
"id": 4,
"type": "PreviewImage",
"pos": [
1284,
380
],
"size": {
"0": 434.666748046875,
"1": 290.66668701171875
},
"flags": {},
"order": 4,
"mode": 0,
"inputs": [
{
"name": "images",
"type": "IMAGE",
"link": 4
}
],
"properties": {
"Node name for S&R": "PreviewImage"
}
},
{
"id": 3,
"type": "LayerStyle_OuterGlow",
"pos": [
925,
381
],
"size": {
"0": 315,
"1": 266
},
"flags": {},
"order": 3,
"mode": 0,
"inputs": [
{
"name": "background_image",
"type": "IMAGE",
"link": 2
},
{
"name": "layer_image",
"type": "IMAGE",
"link": 3
},
{
"name": "layer_mask",
"type": "MASK",
"link": null
}
],
"outputs": [
{
"name": "image",
"type": "IMAGE",
"links": [
4
],
"shape": 3,
"slot_index": 0
}
],
"properties": {
"Node name for S&R": "LayerStyle_OuterGlow"
},
"widgets_values": [
true,
"screen",
100,
8,
48,
25,
"#FFBF30",
"#FE0000"
]
},
{
"id": 5,
"type": "LayerStyle_OuterGlow",
"pos": [
2165.2059106060115,
401.76576118268605
],
"size": {
"0": 315,
"1": 266
},
"flags": {},
"order": 1,
"mode": 0,
"inputs": [
{
"name": "background_image",
"type": "IMAGE",
"link": null
},
{
"name": "layer_image",
"type": "IMAGE",
"link": null
},
{
"name": "layer_mask",
"type": "MASK",
"link": null
}
],
"outputs": [
{
"name": "image",
"type": "IMAGE",
"links": null,
"shape": 3
}
],
"properties": {
"Node name for S&R": "LayerStyle_OuterGlow"
},
"widgets_values": [
true,
"screen",
100,
5,
48,
25,
"#FFBF30",
"#FE0000"
]
}
],
"links": [
[
1,
1,
0,
2,
0,
"IMAGE"
],
[
2,
1,
0,
3,
0,
"IMAGE"
],
[
3,
2,
0,
3,
1,
"IMAGE"
],
[
4,
3,
0,
4,
0,
"IMAGE"
]
],
"groups": [],
"config": {},
"extra": {},
"version": 0.4
}