Commit InnerGlow, InnerShadow and MotionBlur nodes. Renaming all completed nodes. The nodes are divided into 4 groups:LayerStyle, LayerMask, LayerUtility, LayerFilter.

workflows containing old version nodes need to be manually replaced with new version nodes.
This commit is contained in:
chflame163
2024-01-21 00:10:20 +08:00
committed by GitHub
parent 53f0e1a2e1
commit 5d2ab5bf6a
34 changed files with 1591 additions and 860 deletions
+35 -50
View File
@@ -1,12 +1,16 @@
# ComfyUI Layer Style
A set of nodes for ComfyUI that generate image like Adobe Photoshop's Layer Style.
Currently completed the Drop Shadow, OuterGlow, and some auxiliary nodes. follow-up work is in progress.
The completed nodes are as follows, and further work is in progress.
![image](image/title.png)
[中文说明点这里](./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 InnerGlow, InnerShadow and MotionBlur nodes.
* Renaming all completed nodes, the nodes are divided into 4 groups:LayerStyle, LayerMask, LayerUtility, LayerFilter. workflows containing old version nodes need to be manually replaced with new version nodes.
* Fix OuterGlow, add 3 new options: brightness, light_color and glow_color.
* OuterGlow node has undergone significant modifications by adding options for **_brightness_**, **_light_color_**, and **_glow_color_**.
* Commit MaskInvert node.
* Commit ColorPick node.
* Commit Stroke node.
@@ -17,7 +21,7 @@ Currently completed the Drop Shadow, OuterGlow, and some auxiliary nodes. follow
* Commit OuterGlow node.
* Commit DropShadow node.
## Node Description
# LayerStyle
### DropShadow:
Generate shadow
@@ -38,10 +42,6 @@ Node options:
* blur: Shadow blur level.
* shadow_color<sup>4</sup>: Shadow color.
Output type:
* image
### OuterGlow:
Generate outer glow
![image](image/outer_glow_example.png)
@@ -60,10 +60,6 @@ Node options:
* light_color<sup>4</sup>: Light color.
* glow_color<sup>4</sup>: Edge part color of glow.
Output type:
* image
### Stroke:
Generate a stroke of layer。
![image](image/stroke_example.png)
@@ -76,14 +72,31 @@ Node options:
* invert_mask: Whether to reverse the mask.
* blend_mode<sup>3</sup>: Blending mode of stroke.
* opacity: Opacity of stroke.
* inner_stroke<sup>*</sup>: Stroke shrinkage amplitude.
* outer_stroke<sup>*</sup>: Stroke expansion amplitude.
* stroke_grow: Stroke expansion/contraction amplitude, positive values indicate expansion and negative values indicate contraction.
* stroke_width: Stroke width.
* 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.
Output type:
* image
#### Annotation for LayerStyle nodes:
<sup>1</sup> The layer_image, layer_mask and the background_image(if have input), These three items must be of the same size.。
<sup>2</sup> The mask not a mandatory input item. the alpha channel of the image is used by default. If the image input does not include an alpha channel, the entire image's alpha channel will be automatically created. if have masks input simultaneously, the alpha channel will be overwrite by the mask.
<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'.
# LayerMask
### MaskPreview:
Preview the input mask
![image](image/mask_invert.png)
### MaskInvert:
Invert the mask
# LayerUtility
### ImageBlend:
Composit layer image and background image, multiple blend modes are available for option, and transparency can be set.
@@ -98,9 +111,6 @@ Node options:
* blend_mode<sup>3</sup>: Blending mode.
* opacity: Opacity of blend.
Output type:
* image
### ImageOpacity:
Adjust image opacity
![image](image/image_opacity_example.png)
@@ -111,27 +121,6 @@ Node option:
* invert_mask: Whether to reverse the mask.
* opacity: Opacity of image.
Output type:
* image(RGBA)
* mask
### MaskPreview:
Preview the input mask
![image](image/mask_preview_example.png)
input:mask
### MaskInvert:
Invert the mask
![image](image/mask_invert.png)
Input:
* mask
Output type:
* mask
### ColorPicker:
Modify web extensions from [mtb nodes](https://github.com/melMass/comfy_mtb). Select colors on the color palette and output RGB values.
![image](image/color_picker.png)
@@ -142,24 +131,20 @@ Node options:
Output Type:
* string
# LayerUtility
### Annotation:
<sup>1</sup> The layer_image, layer_mask and the background_image(if have input), These three items must be of the same size.。
### MotionBlur:
Make the image motion blur
<sup>2</sup> The mask not a mandatory input item. the alpha channel of the image is used by default. If the image input does not include an alpha channel, the entire image's alpha channel will be automatically created. if have masks input simultaneously, the alpha channel will be overwrite by the mask.
<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'.
Node options:
* angle: The angle of blur.
* blur: The size of blur.
## Example workflow
image Some JSON workflow files in the workflow directory, that is example for ComfyUI.
## The following tasks are in the planned list
* Inner Shadow
* Inner Glow
* Texture
* Color Overlay
* Gradient Overlay
+31 -52
View File
@@ -1,10 +1,13 @@
# ComfyUI Layer Style:
ComfyUI插件,通过一组节点实现仿照Adobe Photoshop的图层样式。
当前已完成Drop Shadow和OuterGlow节点和一些辅助节点,后续工作进行中。
已完成的节点如下,后续工作进行中。
![image](image/title.png)
## 更新说明:
* OuterGlow节点重大修改,增加亮度、灯光颜色、辉光颜色选项。包含旧版节点的工作流需手动替换新版节点。
* 添加InnerGlow, InnerShadow, MotionBlur节点。
* 所有已完成的节点重新命名,节点分为4组:LayerStyle, LayerMask, LayerUtility, LayerFilter。因为重新命名,包含旧版节点的工作流需手动替换新版节点。
* OuterGlow节点修改,增加亮度、灯光颜色、辉光颜色选项。
* 添加MaskInvert节点。
* 添加Stroke节点。
* 添加MaskPreview节点。
@@ -14,13 +17,12 @@ ComfyUI
* 添加OuterGlow节点。
* 首个节点DropShadow提交。
## 节点说明:
# LayerStyle
### DropShadow:
生成阴影。
![image](image/drop_shadow_example.png)
节点选项说明:
![image](image/drop_shadow_node.png)
* background_image<sup>1</sup>: 背景图像。
@@ -35,10 +37,6 @@ ComfyUI
* blur:阴影模糊程度。
* shadow_color<sup>4</sup>: 阴影颜色。
输出:
* image
### OuterGlow:
生成外发光。
![image](image/outer_glow_example.png)
@@ -57,10 +55,6 @@ ComfyUI
* light_color<sup>4</sup>: 发光中心颜色。
* glow_colo<sup>4</sup>: 辉光外围颜色。
输出:
* image
### Stroke:
生成描边。
![image](image/stroke_example.png)
@@ -73,15 +67,28 @@ ComfyUI
* invert_mask: 是否反转遮罩。
* blend_mode<sup>3</sup>: 描边的混合模式。
* opacity: 不透明度。
* inner_stroke<sup>*</sup>: 描边向内收缩幅度。
* outer_stroke<sup>*</sup>:描边向外扩张幅度。
* stroke_grow<sup></sup>: 描边扩张/收缩幅度,正值是扩张,负值是收缩。
* stroke_width<sup></sup>:描边宽度。
* stroke_color<sup>4</sup>: 描边颜色。
<sup>*</sup>描边的宽度等于收缩值加上扩张值。两个值分开设置能更方便的调整边框范围。
#### 节点选项注解:
<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'。
# LayerMask
### MaskPreview:
预览mask
![image](image/mask_invert.png)
### MaskInvert:
mask反转
输出:
* image
# LayerUtility
### ImageBlend:
用于合成图层,提供多种混合模式供选择,可设置透明度。
@@ -96,10 +103,6 @@ ComfyUI
* blend_mode<sup>3</sup>: 图层混合模式。
* opacity: 不透明度。
输出:
* image
### ImageOpacity:
调整图像不透明度。
![image](image/image_opacity_example.png)
@@ -110,28 +113,6 @@ ComfyUI
* invert_mask: 是否反转遮罩。
* opacity: 不透明度。
输出:
* image(RGBA)
* mask
### MaskPreview:
预览mask
![image](image/mask_preview_example.png)
输入:
* mask
### MaskInvert:
mask反转
![image](image/mask_invert.png)
输入:
* mask
输出:
* mask
### ColorPicker:
在色板上选取颜色并输出。
改自[mtb nodes](https://github.com/melMass/comfy_mtb)的web extensions。
@@ -143,13 +124,15 @@ mask
输出:
* string
# LayerUtility
### MotionBlur:
运动模糊。
节点选项说明:
* angle: 模糊角度。
* blur: 模糊大小。
### 节点选项注解:
<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'。
## 使用示例:
@@ -157,13 +140,9 @@ mask
## 以下工作在计划列表中
* Inner Shadow
* Inner Glow
* 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: 64 KiB

After

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 442 KiB

After

Width:  |  Height:  |  Size: 680 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 400 KiB

After

Width:  |  Height:  |  Size: 1013 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 86 KiB

After

Width:  |  Height:  |  Size: 72 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 360 KiB

After

Width:  |  Height:  |  Size: 271 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 637 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 638 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 211 KiB

After

Width:  |  Height:  |  Size: 167 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 630 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 MiB

After

Width:  |  Height:  |  Size: 754 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 628 KiB

After

Width:  |  Height:  |  Size: 614 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 145 KiB

After

Width:  |  Height:  |  Size: 129 KiB

BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 MiB

After

Width:  |  Height:  |  Size: 372 KiB

+4 -4
View File
@@ -23,10 +23,10 @@ class ColorPicker:
RETURN_TYPES = ("STRING",)
RETURN_NAMES = ("value",)
FUNCTION = 'picker'
CATEGORY = '😺dzNodes'
CATEGORY = '😺dzNodes/LayerUtility'
OUTPUT_NODE = True
def picker(self, color, mode,):
def picker(self, color, mode):
ret = color
if ret == 'white':
ret = "#FFFFFF"
@@ -36,9 +36,9 @@ class ColorPicker:
NODE_CLASS_MAPPINGS = {
"LayerStyle_ColorPicker": ColorPicker
"LayerUtility: ColorPicker": ColorPicker
}
NODE_DISPLAY_NAME_MAPPINGS = {
"LayerStyle_ColorPicker": "LayerStyle: ColorPicker"
"LayerUtility: ColorPicker": "LayerUtility: ColorPicker"
}
+8 -15
View File
@@ -15,10 +15,10 @@ class DropShadow:
"invert_mask": ("BOOLEAN", {"default": True}), # 反转mask
"blend_mode": (chop_mode,), # 混合模式
"opacity": ("INT", {"default": 50, "min": 0, "max": 100, "step": 1}), # 透明度
"distance_x": ("INT", {"default": 5, "min": -9999, "max": 9999, "step": 1}), # x_偏移
"distance_y": ("INT", {"default": 5, "min": -9999, "max": 9999, "step": 1}), # y_偏移
"grow": ("INT", {"default": 2, "min": -9999, "max": 9999, "step": 1}), # 扩张
"blur": ("INT", {"default": 15, "min": 0, "max": 100, "step": 1}), # 模糊
"distance_x": ("INT", {"default": 25, "min": -9999, "max": 9999, "step": 1}), # x_偏移
"distance_y": ("INT", {"default": 25, "min": -9999, "max": 9999, "step": 1}), # y_偏移
"grow": ("INT", {"default": 6, "min": -9999, "max": 9999, "step": 1}), # 扩张
"blur": ("INT", {"default": 18, "min": 0, "max": 100, "step": 1}), # 模糊
"shadow_color": ("STRING", {"default": "#000000"}), # 背景颜色
},
"optional": {
@@ -26,20 +26,18 @@ class DropShadow:
}
}
log('DropShadow Processing...')
# RETURN_TYPES = ("IMAGE", "MASK",)
# RETURN_NAMES = ("image", "shadow_mask",)
RETURN_TYPES = ("IMAGE",)
RETURN_NAMES = ("image",)
FUNCTION = 'drop_shadow'
CATEGORY = '😺dzNodes'
CATEGORY = '😺dzNodes/LayerStyle'
OUTPUT_NODE = True
def drop_shadow(self, background_image, layer_image,
invert_mask, blend_mode, opacity, distance_x, distance_y,
grow, blur, shadow_color,
layer_mask=None,
layer_mask=None
):
distance_x = -distance_x
distance_y = -distance_y
_canvas = tensor2pil(background_image).convert('RGB')
@@ -50,23 +48,18 @@ class DropShadow:
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) #扩张,模糊
# 合成阴影
shadow_color = Image.new("RGB", _layer.size, color=shadow_color)
alpha = tensor2pil(shadow_mask).convert('L')
_shadow = chop_image(_canvas, shadow_color, blend_mode, opacity)
_canvas.paste(_shadow, mask=alpha)
# 合成layer
_canvas.paste(_layer, mask=_mask)
ret_image = _canvas
# ret_mask = shadow_mask
# return (pil2tensor(ret_image), ret_mask,)
log('DropShadow Processed.')
return (pil2tensor(ret_image),)
NODE_CLASS_MAPPINGS = {
+5 -7
View File
@@ -24,15 +24,14 @@ class ImageBlend:
RETURN_TYPES = ("IMAGE",)
RETURN_NAMES = ("image",)
FUNCTION = 'image_blend'
CATEGORY = '😺dzNodes'
CATEGORY = '😺dzNodes/LayerUtility'
OUTPUT_NODE = True
def image_blend(self, background_image, layer_image,
invert_mask, blend_mode, opacity,
layer_mask=None,
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]
@@ -40,18 +39,17 @@ class ImageBlend:
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
log('ImageBlend Processed.')
return (pil2tensor(ret_image),)
NODE_CLASS_MAPPINGS = {
"LayerStyle_ImageBlend": ImageBlend
"LayerUtility: ImageBlend": ImageBlend
}
NODE_DISPLAY_NAME_MAPPINGS = {
"LayerStyle_ImageBlend": "LayerStyle: ImageBlend"
"LayerUtility: ImageBlend": "LayerUtility: ImageBlend"
}
+4 -5
View File
@@ -19,11 +19,10 @@ class ImageOpacity:
}
}
log('ImageOpacity Processing...')
RETURN_TYPES = ("IMAGE", "MASK",)
RETURN_NAMES = ("image", "mask",)
FUNCTION = 'image_opacity'
CATEGORY = '😺dzNodes'
CATEGORY = '😺dzNodes/LayerUtility'
OUTPUT_NODE = True
def image_opacity(self, image, opacity, invert_mask,
@@ -51,13 +50,13 @@ class ImageOpacity:
ret_image = Image.merge('RGBA', (R, G, B, ImageChops.invert(ret_mask)))
else:
ret_image = Image.merge('RGBA', (R, G, B, ret_mask))
log('ImageOpacity Processed.')
return (pil2tensor(ret_image), image2mask(ret_mask),)
NODE_CLASS_MAPPINGS = {
"LayerStyle_ImageOpacity": ImageOpacity
"LayerUtility: ImageOpacity": ImageOpacity
}
NODE_DISPLAY_NAME_MAPPINGS = {
"LayerStyle_ImageOpacity": "LayerStyle: ImageOpacity"
"LayerUtility: ImageOpacity": "LayerUtility: ImageOpacity"
}
+53 -31
View File
@@ -12,6 +12,8 @@ def log(message):
name = 'LayerStyle'
print(f"# 😺dzNodes: {name} -> {message}")
'''Converter'''
def cv22pil(cv2_img:np.ndarray) -> Image:
cv2_img = cv2.cvtColor(cv2_img, cv2.COLOR_BGR2RGB)
return Image.fromarray(cv2_img)
@@ -54,9 +56,7 @@ def mask2image(mask:torch.Tensor) -> Image:
_image, Image.new("RGBA", _mask.size, color='black'), _mask)
return _image
def mask_invert(mask:torch.Tensor) -> torch.Tensor:
_image = mask2image(mask)
return image2mask(ImageChops.invert(_image))
'''Image Functions'''
def shift_image(image:Image, distance_x:int, distance_y:int) -> Image:
bkcolor = (0, 0, 0)
@@ -65,14 +65,13 @@ def shift_image(image:Image, distance_x:int, distance_y:int) -> Image:
ret_image = Image.new('RGB', size=(width, height), color=bkcolor)
for x in range(width):
for y in range(height):
if x > -distance_x and y > -distance_y:
if x + distance_x < width and y + distance_y < height:
if x > -distance_x and y > -distance_y: # 防止回转
if x + distance_x < width and y + distance_y < height: # 防止越界
pixel = image.getpixel((x + distance_x, y + distance_y))
ret_image.putpixel((x, y), pixel)
return ret_image
def chop_image(background_image:Image, layer_image:Image, blend_mode:str, opacity:int) -> Image:
ret_image = background_image
if blend_mode == 'normal':
ret_image = layer_image
@@ -90,16 +89,43 @@ def chop_image(background_image:Image, layer_image:Image, blend_mode:str, opacit
ret_image = ImageChops.darker(background_image, layer_image)
if blend_mode == 'lighter':
ret_image = ImageChops.lighter(background_image, layer_image)
# opacity
if opacity == 0:
ret_image = background_image
elif opacity < 100:
alpha = 1.0 - float(opacity) / 100
ret_image = Image.blend(ret_image, background_image, alpha)
return ret_image
def remove_background(image:Image, mask:Image, color:str) -> Image:
width = image.width
height = image.height
ret_image = Image.new('RGB', size=(width, height), color=color)
ret_image.paste(image, mask=mask)
return ret_image
def motion_blur(image:Image, angle:int, blur:int) -> Image:
angle += 45
blur *= 5
image = np.array(pil2cv2(image))
M = cv2.getRotationMatrix2D((blur / 2, blur / 2), angle, 1)
motion_blur_kernel = np.diag(np.ones(blur))
motion_blur_kernel = cv2.warpAffine(motion_blur_kernel, M, (blur, blur))
motion_blur_kernel = motion_blur_kernel / blur
blurred = cv2.filter2D(image, -1, motion_blur_kernel)
# convert to uint8
cv2.normalize(blurred, blurred, 0, 255, cv2.NORM_MINMAX)
blurred = np.array(blurred, dtype=np.uint8)
ret_image = cv22pil(blurred)
return ret_image
def direction_blur(image:Image, angle:int, blur:int, color:str) -> Image:
ret_image = image
return ret_image
'''Mask Functions'''
def expand_mask(mask:torch.Tensor, grow:int, blur:int) -> torch.Tensor:
# grow
c = 0
@@ -122,54 +148,50 @@ def expand_mask(mask:torch.Tensor, grow:int, blur:int) -> torch.Tensor:
pil_image = tensor2pil(tensor.cpu().detach())
pil_image = pil_image.filter(ImageFilter.GaussianBlur(blur))
out[idx] = pil2tensor(pil_image)
ret_mask = torch.cat(out, dim=0)
return ret_mask
def remove_background(image:Image, mask:Image, color:str) -> Image:
width = image.width
height = image.height
ret_image = Image.new('RGB', size=(width, height), color=color)
ret_image.paste(image, mask=mask)
return ret_image
def mask_invert(mask:torch.Tensor) -> torch.Tensor:
_image = mask2image(mask)
return image2mask(ImageChops.invert(_image))
def subtract_mask(masks_a, masks_b):
def subtract_mask(masks_a:torch.Tensor, masks_b:torch.Tensor) -> torch.Tensor:
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 Functions'''
def RGB_to_Hex(RGB) -> str:
color = '#'
for i in _rgb:
for i in RGB:
num = int(i)
color += str(hex(num))[-2:].replace('x', '0').upper()
return color
def Hex_to_RGB(inhex):
def Hex_to_RGB(inhex) -> tuple:
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
'''Value Functions'''
def step_color(start_color, end_color, total_step, step):
def step_value(start_value, end_value, total_step, step) -> float: # 按当前步数在总步数中的位置返回比例值
factor = step / total_step
return (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),
ret_color = (int(step_value(start_R, end_R, total_step, step)),
int(step_value(start_G, end_G, total_step, step)),
int(step_value(start_B, end_B, total_step, step)),
)
if isinstance(start_color, str):
return RGB_to_Hex(ret_color)
else:
return ret_color
return ret_color
+75
View File
@@ -0,0 +1,75 @@
from .imagefunc import *
class InnerGlow:
def __init__(self):
pass
@classmethod
def INPUT_TYPES(self):
chop_mode = ['screen', 'add', 'lighter', 'normal', 'multply', 'subtract','difference','darker']
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}), # 透明度
"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",)
RETURN_NAMES = ("image",)
FUNCTION = 'inner_glow'
CATEGORY = '😺dzNodes/LayerStyle'
OUTPUT_NODE = True
def inner_glow(self, background_image, layer_image,
invert_mask, blend_mode, opacity,
brightness, glow_range, blur, light_color, 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 layer_mask is not None:
if invert_mask:
layer_mask = 1 - layer_mask
_mask = mask2image(layer_mask).convert('L')
blur_factor = blur / 20.0
grow = glow_range
inner_mask = _mask
for x in range(brightness):
blur = int(grow * blur_factor)
_color = step_color(glow_color, light_color, brightness, x)
glow_mask = expand_mask(image2mask(inner_mask), -grow, blur) #扩张,模糊
# 合成glow
color_image = Image.new("RGB", _layer.size, color=_color)
alpha = tensor2pil(mask_invert(glow_mask)).convert('L')
_glow = chop_image(_layer, color_image, blend_mode, int(step_value(1, opacity, brightness, x)))
_layer.paste(_glow, mask=alpha)
grow = grow - int(glow_range/brightness)
# 合成layer
_layer.paste(_canvas, mask=ImageChops.invert(_mask))
ret_image = _layer
log('InnerGLow Advance Processed.')
return (pil2tensor(ret_image),)
NODE_CLASS_MAPPINGS = {
"LayerStyle: InnerGlow": InnerGlow
}
NODE_DISPLAY_NAME_MAPPINGS = {
"LayerStyle: InnerGlow": "LayerStyle: InnerGlow"
}
+72
View File
@@ -0,0 +1,72 @@
from .imagefunc import *
class InnerShadow:
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": 50, "min": 0, "max": 100, "step": 1}), # 透明度
"distance_x": ("INT", {"default": 5, "min": -9999, "max": 9999, "step": 1}), # x_偏移
"distance_y": ("INT", {"default": 5, "min": -9999, "max": 9999, "step": 1}), # y_偏移
"grow": ("INT", {"default": 2, "min": -9999, "max": 9999, "step": 1}), # 扩张
"blur": ("INT", {"default": 15, "min": 0, "max": 100, "step": 1}), # 模糊
"shadow_color": ("STRING", {"default": "#000000"}), # 背景颜色
},
"optional": {
"layer_mask": ("MASK",), #
}
}
RETURN_TYPES = ("IMAGE",)
RETURN_NAMES = ("image",)
FUNCTION = 'inner_shadow'
CATEGORY = '😺dzNodes/LayerStyle'
OUTPUT_NODE = True
def inner_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
_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) #扩张,模糊
# 合成阴影
shadow_color = Image.new("RGB", _layer.size, color=shadow_color)
alpha = tensor2pil(shadow_mask).convert('L')
_shadow = chop_image(_layer, shadow_color, blend_mode, opacity)
_layer.paste(_shadow, mask=ImageChops.invert(alpha))
# 合成layer
_canvas.paste(_layer, mask=_mask)
ret_image = _canvas
log('InnerShadow Processed.')
return (pil2tensor(ret_image),)
NODE_CLASS_MAPPINGS = {
"LayerStyle: InnerShadow": InnerShadow
}
NODE_DISPLAY_NAME_MAPPINGS = {
"LayerStyle: InnerShadow": "LayerStyle: InnerShadow"
}
+4 -4
View File
@@ -18,17 +18,17 @@ class MaskInvert:
RETURN_TYPES = ("MASK",)
RETURN_NAMES = ("mask",)
FUNCTION = 'mask_invert'
CATEGORY = '😺dzNodes'
CATEGORY = '😺dzNodes/LayerMask'
OUTPUT_NODE = True
def mask_invert(self,mask,):
def mask_invert(self,mask):
return (mask_invert(mask),)
NODE_CLASS_MAPPINGS = {
"LayerStyle_MaskInvert": MaskInvert
"LayerMask: MaskInvert": MaskInvert
}
NODE_DISPLAY_NAME_MAPPINGS = {
"LayerStyle_MaskInvert": "LayerStyle: MaskInvert"
"LayerMask: MaskInvert": "LayerMask: MaskInvert"
}
+3 -3
View File
@@ -17,16 +17,16 @@ class MaskPreview(SaveImage):
}
FUNCTION = "mask_preview"
CATEGORY = '😺dzNodes'
CATEGORY = '😺dzNodes/LayerMask'
def mask_preview(self, mask):
preview = mask.reshape((-1, 1, mask.shape[-2], mask.shape[-1])).movedim(1, -1).expand(-1, -1, -1, 3)
return self.save_images(preview, "MaskPreview")
NODE_CLASS_MAPPINGS = {
"LayerStyle_MaskPreview": MaskPreview
"LayerMask: MaskPreview": MaskPreview
}
NODE_DISPLAY_NAME_MAPPINGS = {
"LayerStyle_MaskPreview": "LayerStyle: MaskPreview"
"LayerMask: MaskPreview": "LayerMask: MaskPreview"
}
+40
View File
@@ -0,0 +1,40 @@
from .imagefunc import *
class MotionBlur:
def __init__(self):
pass
@classmethod
def INPUT_TYPES(self):
return {
"required": {
"image": ("IMAGE", ), #
"angle": ("INT", {"default": 0, "min": -90, "max": 90, "step": 1}), # 角度
"blur": ("INT", {"default": 20, "min": 1, "max": 999, "step": 1}), # 模糊
},
"optional": {
}
}
RETURN_TYPES = ("IMAGE",)
RETURN_NAMES = ("image",)
FUNCTION = 'motion_blur'
CATEGORY = '😺dzNodes/LayerFilter'
OUTPUT_NODE = True
def motion_blur(self, image, angle, blur):
_canvas = tensor2pil(image).convert('RGB')
ret_image = motion_blur(_canvas, angle, blur)
log('MotionBlur Processed.')
return (pil2tensor(ret_image),)
NODE_CLASS_MAPPINGS = {
"LayerFilter: MotionBlur": MotionBlur
}
NODE_DISPLAY_NAME_MAPPINGS = {
"LayerFilter: MotionBlur": "LayerFilter: MotionBlur"
}
+4 -6
View File
@@ -29,16 +29,15 @@ class OuterGlow:
RETURN_TYPES = ("IMAGE",)
RETURN_NAMES = ("image",)
FUNCTION = 'outer_glow'
CATEGORY = '😺dzNodes'
CATEGORY = '😺dzNodes/LayerStyle'
OUTPUT_NODE = True
def outer_glow(self, background_image, layer_image,
invert_mask, blend_mode, opacity,
brightness, glow_range, blur, light_color, glow_color,
layer_mask=None,
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]
@@ -56,14 +55,13 @@ class OuterGlow:
# 合成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))
_glow = chop_image(_canvas, color_image, blend_mode, int(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
log('OuterGLow Advance Processed.')
return (pil2tensor(ret_image),)
NODE_CLASS_MAPPINGS = {
+12 -9
View File
@@ -15,8 +15,8 @@ class Stroke:
"invert_mask": ("BOOLEAN", {"default": True}), # 反转mask
"blend_mode": (chop_mode,), # 混合模式
"opacity": ("INT", {"default": 100, "min": 0, "max": 100, "step": 1}), # 透明度
"inner_stroke": ("INT", {"default": 4, "min": 0, "max": 9999, "step": 1}), # 收缩值
"outer_stroke": ("INT", {"default": 4, "min": 0, "max": 9999, "step": 1}), # 扩张值
"stroke_grow": ("INT", {"default": 0, "min": -999, "max": 999, "step": 1}), # 收缩值
"stroke_width": ("INT", {"default": 8, "min": 0, "max": 999, "step": 1}), # 扩张值
"blur": ("INT", {"default": 0, "min": 0, "max": 100, "step": 1}), # 模糊
"stroke_color": ("STRING", {"default": "#FF0000"}), # 描边颜色
},
@@ -28,16 +28,15 @@ class Stroke:
RETURN_TYPES = ("IMAGE",)
RETURN_NAMES = ("image",)
FUNCTION = 'stroke'
CATEGORY = '😺dzNodes'
CATEGORY = '😺dzNodes/LayerStyle'
OUTPUT_NODE = True
def stroke(self, background_image, layer_image,
invert_mask, blend_mode, opacity,
inner_stroke, outer_stroke, blur, stroke_color,
layer_mask=None,
stroke_grow, stroke_width, blur, stroke_color,
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]
@@ -46,7 +45,10 @@ class Stroke:
layer_mask = 1 - layer_mask
_mask = mask2image(layer_mask).convert('L')
inner_mask = expand_mask(image2mask(_mask), -inner_stroke, blur)
grow_offset = int(stroke_width / 2)
inner_stroke = stroke_grow - grow_offset
outer_stroke = inner_stroke + stroke_width
inner_mask = expand_mask(image2mask(_mask), inner_stroke, blur)
outer_mask = expand_mask(image2mask(_mask), outer_stroke, blur)
strock_mask = subtract_mask(outer_mask, inner_mask)
color_image = Image.new('RGB', size=_layer.size, color=stroke_color)
@@ -54,12 +56,13 @@ class Stroke:
_canvas.paste(_layer, mask=_mask)
_canvas.paste(blend_image, mask=tensor2pil(strock_mask))
ret_image = _canvas
log('Stroke Processed.')
return (pil2tensor(ret_image),)
NODE_CLASS_MAPPINGS = {
"LayerStyle_Stroke": Stroke
"LayerStyle: Stroke": Stroke
}
NODE_DISPLAY_NAME_MAPPINGS = {
"LayerStyle_Stroke": "LayerStyle: Stroke"
"LayerStyle: Stroke": "LayerStyle: Stroke"
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 68 KiB

After

Width:  |  Height:  |  Size: 57 KiB

+205 -206
View File
@@ -1,207 +1,206 @@
{
"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": [
180,
-680
],
"size": {
"0": 315,
"1": 314
},
"flags": {},
"order": 0,
"mode": 0,
"outputs": [
{
"name": "IMAGE",
"type": "IMAGE",
"links": [
55
],
"shape": 3,
"slot_index": 0
},
{
"name": "MASK",
"type": "MASK",
"links": [
56
],
"shape": 3,
"slot_index": 1
}
],
"properties": {
"Node name for S&R": "LoadImage"
},
"widgets_values": [
"512x512.png",
"image"
]
},
{
"id": 3,
"type": "LoadImage",
"pos": [
-160,
-680
],
"size": {
"0": 315,
"1": 314
},
"flags": {},
"order": 1,
"mode": 0,
"outputs": [
{
"name": "IMAGE",
"type": "IMAGE",
"links": [
54
],
"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"
]
}
],
"links": [
[
54,
3,
0,
22,
0,
"IMAGE"
],
[
55,
2,
0,
22,
1,
"IMAGE"
],
[
56,
2,
1,
22,
2,
"MASK"
],
[
58,
22,
0,
23,
0,
"IMAGE"
]
],
"groups": [],
"config": {},
"extra": {},
"version": 0.4
{
"last_node_id": 18,
"last_link_id": 35,
"nodes": [
{
"id": 4,
"type": "PreviewImage",
"pos": [
1360,
390
],
"size": [
310.00006103515625,
308.33331298828125
],
"flags": {},
"order": 3,
"mode": 0,
"inputs": [
{
"name": "images",
"type": "IMAGE",
"link": 34
}
],
"properties": {
"Node name for S&R": "PreviewImage"
}
},
{
"id": 2,
"type": "LoadImage",
"pos": [
310,
390
],
"size": {
"0": 315,
"1": 314
},
"flags": {},
"order": 0,
"mode": 0,
"outputs": [
{
"name": "IMAGE",
"type": "IMAGE",
"links": [
32
],
"shape": 3,
"slot_index": 0
},
{
"name": "MASK",
"type": "MASK",
"links": null,
"shape": 3
}
],
"properties": {
"Node name for S&R": "LoadImage"
},
"widgets_values": [
"512x512bk.jpg",
"image"
]
},
{
"id": 18,
"type": "LayerStyle_DropShadow",
"pos": [
1013,
414
],
"size": {
"0": 315,
"1": 266
},
"flags": {},
"order": 2,
"mode": 0,
"inputs": [
{
"name": "background_image",
"type": "IMAGE",
"link": 32
},
{
"name": "layer_image",
"type": "IMAGE",
"link": 33
},
{
"name": "layer_mask",
"type": "MASK",
"link": 35
}
],
"outputs": [
{
"name": "image",
"type": "IMAGE",
"links": [
34
],
"shape": 3,
"slot_index": 0
}
],
"properties": {
"Node name for S&R": "LayerStyle_DropShadow"
},
"widgets_values": [
true,
"normal",
50,
25,
25,
6,
18,
"#000000"
]
},
{
"id": 15,
"type": "LoadImage",
"pos": [
660,
399
],
"size": {
"0": 315,
"1": 314
},
"flags": {},
"order": 1,
"mode": 0,
"outputs": [
{
"name": "IMAGE",
"type": "IMAGE",
"links": [
33
],
"shape": 3,
"slot_index": 0
},
{
"name": "MASK",
"type": "MASK",
"links": [
35
],
"shape": 3,
"slot_index": 1
}
],
"properties": {
"Node name for S&R": "LoadImage"
},
"widgets_values": [
"512x512 (14).png",
"image"
]
}
],
"links": [
[
32,
2,
0,
18,
0,
"IMAGE"
],
[
33,
15,
0,
18,
1,
"IMAGE"
],
[
34,
18,
0,
4,
0,
"IMAGE"
],
[
35,
15,
1,
18,
2,
"MASK"
]
],
"groups": [],
"config": {},
"extra": {},
"version": 0.4
}
+425 -201
View File
@@ -1,202 +1,426 @@
{
"last_node_id": 5,
"last_link_id": 5,
"nodes": [
{
"id": 1,
"type": "LoadImage",
"pos": [
327,
175
],
"size": {
"0": 315,
"1": 314
},
"flags": {},
"order": 0,
"mode": 0,
"outputs": [
{
"name": "IMAGE",
"type": "IMAGE",
"links": [
1
],
"shape": 3,
"slot_index": 0
},
{
"name": "MASK",
"type": "MASK",
"links": null,
"shape": 3
}
],
"properties": {
"Node name for S&R": "LoadImage"
},
"widgets_values": [
"512x512bkgd (3).jpg",
"image"
]
},
{
"id": 2,
"type": "LoadImage",
"pos": [
680,
176
],
"size": {
"0": 315,
"1": 314
},
"flags": {},
"order": 1,
"mode": 0,
"outputs": [
{
"name": "IMAGE",
"type": "IMAGE",
"links": [
2
],
"shape": 3,
"slot_index": 0
},
{
"name": "MASK",
"type": "MASK",
"links": [
5
],
"shape": 3,
"slot_index": 1
}
],
"properties": {
"Node name for S&R": "LoadImage"
},
"widgets_values": [
"512x512 (5).png",
"image"
]
},
{
"id": 3,
"type": "LayerStyle_ImageBlend",
"pos": [
1041,
203
],
"size": {
"0": 315,
"1": 146
},
"flags": {},
"order": 2,
"mode": 0,
"inputs": [
{
"name": "background_image",
"type": "IMAGE",
"link": 1
},
{
"name": "layer_image",
"type": "IMAGE",
"link": 2
},
{
"name": "layer_mask",
"type": "MASK",
"link": 5
}
],
"outputs": [
{
"name": "image",
"type": "IMAGE",
"links": [
4
],
"shape": 3,
"slot_index": 0
}
],
"properties": {
"Node name for S&R": "LayerStyle_ImageBlend"
},
"widgets_values": [
true,
"subtract",
50
]
},
{
"id": 4,
"type": "SaveImage",
"pos": [
1401,
195
],
"size": [
315,
270
],
"flags": {},
"order": 3,
"mode": 0,
"inputs": [
{
"name": "images",
"type": "IMAGE",
"link": 4
}
],
"properties": {},
"widgets_values": [
"ComfyUI"
]
}
],
"links": [
[
1,
1,
0,
3,
0,
"IMAGE"
],
[
2,
2,
0,
3,
1,
"IMAGE"
],
[
4,
3,
0,
4,
0,
"IMAGE"
],
[
5,
2,
1,
3,
2,
"MASK"
]
],
"groups": [],
"config": {},
"extra": {},
"version": 0.4
{
"last_node_id": 10,
"last_link_id": 17,
"nodes": [
{
"id": 6,
"type": "LayerUtility: ImageBlend",
"pos": [
1030,
370
],
"size": {
"0": 315,
"1": 146
},
"flags": {},
"order": 2,
"mode": 0,
"inputs": [
{
"name": "background_image",
"type": "IMAGE",
"link": 6
},
{
"name": "layer_image",
"type": "IMAGE",
"link": 7
},
{
"name": "layer_mask",
"type": "MASK",
"link": 8
}
],
"outputs": [
{
"name": "image",
"type": "IMAGE",
"links": [
9
],
"shape": 3,
"slot_index": 0
}
],
"properties": {
"Node name for S&R": "LayerUtility: ImageBlend"
},
"widgets_values": [
true,
"subtract",
31
]
},
{
"id": 4,
"type": "SaveImage",
"pos": [
1370,
120
],
"size": [
282.3333740234375,
289.66668701171875
],
"flags": {},
"order": 5,
"mode": 0,
"inputs": [
{
"name": "images",
"type": "IMAGE",
"link": 9
}
],
"properties": {},
"widgets_values": [
"ComfyUI"
]
},
{
"id": 7,
"type": "LayerUtility: ImageBlend",
"pos": [
1030,
570
],
"size": {
"0": 315,
"1": 146
},
"flags": {},
"order": 3,
"mode": 0,
"inputs": [
{
"name": "background_image",
"type": "IMAGE",
"link": 10
},
{
"name": "layer_image",
"type": "IMAGE",
"link": 11
},
{
"name": "layer_mask",
"type": "MASK",
"link": 12
}
],
"outputs": [
{
"name": "image",
"type": "IMAGE",
"links": [
13
],
"shape": 3,
"slot_index": 0
}
],
"properties": {
"Node name for S&R": "LayerUtility: ImageBlend"
},
"widgets_values": [
true,
"lighter",
100
]
},
{
"id": 2,
"type": "LoadImage",
"pos": [
670,
370
],
"size": {
"0": 315,
"1": 314
},
"flags": {},
"order": 0,
"mode": 0,
"outputs": [
{
"name": "IMAGE",
"type": "IMAGE",
"links": [
7,
11,
15
],
"shape": 3,
"slot_index": 0
},
{
"name": "MASK",
"type": "MASK",
"links": [
8,
12,
16
],
"shape": 3,
"slot_index": 1
}
],
"properties": {
"Node name for S&R": "LoadImage"
},
"widgets_values": [
"512x512 (5).png",
"image"
]
},
{
"id": 9,
"type": "LayerUtility: ImageBlend",
"pos": [
1030,
760
],
"size": {
"0": 315,
"1": 146
},
"flags": {},
"order": 4,
"mode": 0,
"inputs": [
{
"name": "background_image",
"type": "IMAGE",
"link": 14
},
{
"name": "layer_image",
"type": "IMAGE",
"link": 15
},
{
"name": "layer_mask",
"type": "MASK",
"link": 16
}
],
"outputs": [
{
"name": "image",
"type": "IMAGE",
"links": [
17
],
"shape": 3,
"slot_index": 0
}
],
"properties": {
"Node name for S&R": "LayerUtility: ImageBlend"
},
"widgets_values": [
true,
"multply",
68
]
},
{
"id": 1,
"type": "LoadImage",
"pos": [
320,
370
],
"size": {
"0": 315,
"1": 314
},
"flags": {},
"order": 1,
"mode": 0,
"outputs": [
{
"name": "IMAGE",
"type": "IMAGE",
"links": [
6,
10,
14
],
"shape": 3,
"slot_index": 0
},
{
"name": "MASK",
"type": "MASK",
"links": null,
"shape": 3
}
],
"properties": {
"Node name for S&R": "LoadImage"
},
"widgets_values": [
"512x512bkgd (3).jpg",
"image"
]
},
{
"id": 8,
"type": "SaveImage",
"pos": [
1371,
453
],
"size": {
"0": 282.3333740234375,
"1": 289.66668701171875
},
"flags": {},
"order": 6,
"mode": 0,
"inputs": [
{
"name": "images",
"type": "IMAGE",
"link": 13
}
],
"properties": {},
"widgets_values": [
"ComfyUI"
]
},
{
"id": 10,
"type": "SaveImage",
"pos": [
1370,
786
],
"size": {
"0": 282.3333740234375,
"1": 289.66668701171875
},
"flags": {},
"order": 7,
"mode": 0,
"inputs": [
{
"name": "images",
"type": "IMAGE",
"link": 17
}
],
"properties": {},
"widgets_values": [
"ComfyUI"
]
}
],
"links": [
[
6,
1,
0,
6,
0,
"IMAGE"
],
[
7,
2,
0,
6,
1,
"IMAGE"
],
[
8,
2,
1,
6,
2,
"MASK"
],
[
9,
6,
0,
4,
0,
"IMAGE"
],
[
10,
1,
0,
7,
0,
"IMAGE"
],
[
11,
2,
0,
7,
1,
"IMAGE"
],
[
12,
2,
1,
7,
2,
"MASK"
],
[
13,
7,
0,
8,
0,
"IMAGE"
],
[
14,
1,
0,
9,
0,
"IMAGE"
],
[
15,
2,
0,
9,
1,
"IMAGE"
],
[
16,
2,
1,
9,
2,
"MASK"
],
[
17,
9,
0,
10,
0,
"IMAGE"
]
],
"groups": [],
"config": {},
"extra": {},
"version": 0.4
}
+206
View File
@@ -0,0 +1,206 @@
{
"last_node_id": 16,
"last_link_id": 27,
"nodes": [
{
"id": 4,
"type": "PreviewImage",
"pos": [
1360,
390
],
"size": [
310.00006103515625,
308.33331298828125
],
"flags": {},
"order": 3,
"mode": 0,
"inputs": [
{
"name": "images",
"type": "IMAGE",
"link": 27
}
],
"properties": {
"Node name for S&R": "PreviewImage"
}
},
{
"id": 2,
"type": "LoadImage",
"pos": [
310,
390
],
"size": {
"0": 315,
"1": 314
},
"flags": {},
"order": 0,
"mode": 0,
"outputs": [
{
"name": "IMAGE",
"type": "IMAGE",
"links": [
24
],
"shape": 3,
"slot_index": 0
},
{
"name": "MASK",
"type": "MASK",
"links": null,
"shape": 3
}
],
"properties": {
"Node name for S&R": "LoadImage"
},
"widgets_values": [
"512x512bk.jpg",
"image"
]
},
{
"id": 15,
"type": "LoadImage",
"pos": [
660,
394
],
"size": {
"0": 315,
"1": 314
},
"flags": {},
"order": 1,
"mode": 0,
"outputs": [
{
"name": "IMAGE",
"type": "IMAGE",
"links": [
25
],
"shape": 3,
"slot_index": 0
},
{
"name": "MASK",
"type": "MASK",
"links": [
26
],
"shape": 3,
"slot_index": 1
}
],
"properties": {
"Node name for S&R": "LoadImage"
},
"widgets_values": [
"512x512 (14).png",
"image"
]
},
{
"id": 16,
"type": "LayerStyle: InnerGlow",
"pos": [
1013,
419
],
"size": {
"0": 315,
"1": 266
},
"flags": {},
"order": 2,
"mode": 0,
"inputs": [
{
"name": "background_image",
"type": "IMAGE",
"link": 24
},
{
"name": "layer_image",
"type": "IMAGE",
"link": 25
},
{
"name": "layer_mask",
"type": "MASK",
"link": 26
}
],
"outputs": [
{
"name": "image",
"type": "IMAGE",
"links": [
27
],
"shape": 3,
"slot_index": 0
}
],
"properties": {
"Node name for S&R": "LayerStyle: InnerGlow"
},
"widgets_values": [
true,
"screen",
100,
12,
26,
12,
"#FFBF30",
"#FE0000"
]
}
],
"links": [
[
24,
2,
0,
16,
0,
"IMAGE"
],
[
25,
15,
0,
16,
1,
"IMAGE"
],
[
26,
15,
1,
16,
2,
"MASK"
],
[
27,
16,
0,
4,
0,
"IMAGE"
]
],
"groups": [],
"config": {},
"extra": {},
"version": 0.4
}
+206
View File
@@ -0,0 +1,206 @@
{
"last_node_id": 19,
"last_link_id": 39,
"nodes": [
{
"id": 4,
"type": "PreviewImage",
"pos": [
1360,
390
],
"size": [
310.00006103515625,
308.33331298828125
],
"flags": {},
"order": 3,
"mode": 0,
"inputs": [
{
"name": "images",
"type": "IMAGE",
"link": 39
}
],
"properties": {
"Node name for S&R": "PreviewImage"
}
},
{
"id": 2,
"type": "LoadImage",
"pos": [
310,
390
],
"size": {
"0": 315,
"1": 314
},
"flags": {},
"order": 0,
"mode": 0,
"outputs": [
{
"name": "IMAGE",
"type": "IMAGE",
"links": [
36
],
"shape": 3,
"slot_index": 0
},
{
"name": "MASK",
"type": "MASK",
"links": null,
"shape": 3
}
],
"properties": {
"Node name for S&R": "LoadImage"
},
"widgets_values": [
"512x512bk.jpg",
"image"
]
},
{
"id": 15,
"type": "LoadImage",
"pos": [
660,
399
],
"size": {
"0": 315,
"1": 314
},
"flags": {},
"order": 1,
"mode": 0,
"outputs": [
{
"name": "IMAGE",
"type": "IMAGE",
"links": [
37
],
"shape": 3,
"slot_index": 0
},
{
"name": "MASK",
"type": "MASK",
"links": [
38
],
"shape": 3,
"slot_index": 1
}
],
"properties": {
"Node name for S&R": "LoadImage"
},
"widgets_values": [
"512x512 (14).png",
"image"
]
},
{
"id": 19,
"type": "LayerStyle: InnerShadow",
"pos": [
1014,
417
],
"size": {
"0": 315,
"1": 266
},
"flags": {},
"order": 2,
"mode": 0,
"inputs": [
{
"name": "background_image",
"type": "IMAGE",
"link": 36
},
{
"name": "layer_image",
"type": "IMAGE",
"link": 37
},
{
"name": "layer_mask",
"type": "MASK",
"link": 38
}
],
"outputs": [
{
"name": "image",
"type": "IMAGE",
"links": [
39
],
"shape": 3,
"slot_index": 0
}
],
"properties": {
"Node name for S&R": "LayerStyle: InnerShadow"
},
"widgets_values": [
true,
"normal",
100,
5,
5,
2,
15,
"#000000"
]
}
],
"links": [
[
36,
2,
0,
19,
0,
"IMAGE"
],
[
37,
15,
0,
19,
1,
"IMAGE"
],
[
38,
15,
1,
19,
2,
"MASK"
],
[
39,
19,
0,
4,
0,
"IMAGE"
]
],
"groups": [],
"config": {},
"extra": {},
"version": 0.4
}
+75 -143
View File
@@ -1,16 +1,41 @@
{
"last_node_id": 5,
"last_link_id": 4,
"last_node_id": 20,
"last_link_id": 43,
"nodes": [
{
"id": 1,
"id": 4,
"type": "PreviewImage",
"pos": [
1360,
390
],
"size": [
310.00006103515625,
308.33331298828125
],
"flags": {},
"order": 3,
"mode": 0,
"inputs": [
{
"name": "images",
"type": "IMAGE",
"link": 43
}
],
"properties": {
"Node name for S&R": "PreviewImage"
}
},
{
"id": 2,
"type": "LoadImage",
"pos": [
279,
378
310,
390
],
"size": {
"0": 279.00006103515625,
"0": 315,
"1": 314
},
"flags": {},
@@ -21,8 +46,7 @@
"name": "IMAGE",
"type": "IMAGE",
"links": [
1,
2
40
],
"shape": 3,
"slot_index": 0
@@ -38,120 +62,81 @@
"Node name for S&R": "LoadImage"
},
"widgets_values": [
"D04QPvc (7).jpg",
"512x512bk.jpg",
"image"
]
},
{
"id": 2,
"type": "Image Remove Background Rembg (mtb)",
"id": 15,
"type": "LoadImage",
"pos": [
597,
405
660,
399
],
"size": {
"0": 294,
"1": 230
"0": 315,
"1": 314
},
"flags": {},
"order": 2,
"order": 1,
"mode": 0,
"inputs": [
{
"name": "image",
"type": "IMAGE",
"link": 1
}
],
"outputs": [
{
"name": "Image (rgba)",
"name": "IMAGE",
"type": "IMAGE",
"links": [
3
41
],
"shape": 3,
"slot_index": 0
},
{
"name": "Mask",
"name": "MASK",
"type": "MASK",
"links": null,
"shape": 3
},
{
"name": "Image",
"type": "IMAGE",
"links": null,
"shape": 3
"links": [
42
],
"shape": 3,
"slot_index": 1
}
],
"properties": {
"Node name for S&R": "Image Remove Background Rembg (mtb)"
"Node name for S&R": "LoadImage"
},
"widgets_values": [
false,
240,
10,
10,
false,
"#000000"
"512x512 (14).png",
"image"
]
},
{
"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,
"id": 20,
"type": "LayerStyle_OuterGlow",
"pos": [
925,
381
1012,
423
],
"size": {
"0": 315,
"1": 266
},
"flags": {},
"order": 3,
"order": 2,
"mode": 0,
"inputs": [
{
"name": "background_image",
"type": "IMAGE",
"link": 2
"link": 40
},
{
"name": "layer_image",
"type": "IMAGE",
"link": 3
"link": 41
},
{
"name": "layer_mask",
"type": "MASK",
"link": null
"link": 42
}
],
"outputs": [
@@ -159,7 +144,7 @@
"name": "image",
"type": "IMAGE",
"links": [
4
43
],
"shape": 3,
"slot_index": 0
@@ -178,89 +163,36 @@
"#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,
40,
2,
0,
20,
0,
"IMAGE"
],
[
2,
1,
41,
15,
0,
3,
0,
"IMAGE"
],
[
3,
2,
0,
3,
20,
1,
"IMAGE"
],
[
4,
3,
42,
15,
1,
20,
2,
"MASK"
],
[
43,
20,
0,
4,
0,
+124 -124
View File
@@ -1,68 +1,38 @@
{
"last_node_id": 15,
"last_link_id": 18,
"last_node_id": 21,
"last_link_id": 47,
"nodes": [
{
"id": 1,
"type": "LayerStyle_Stroke",
"id": 4,
"type": "PreviewImage",
"pos": [
758,
309
1360,
390
],
"size": [
310.00006103515625,
308.33331298828125
],
"size": {
"0": 315,
"1": 242
},
"flags": {},
"order": 2,
"order": 3,
"mode": 0,
"inputs": [
{
"name": "background_image",
"name": "images",
"type": "IMAGE",
"link": 16
},
{
"name": "layer_image",
"type": "IMAGE",
"link": 10
},
{
"name": "layer_mask",
"type": "MASK",
"link": 3
}
],
"outputs": [
{
"name": "image",
"type": "IMAGE",
"links": [
4
],
"shape": 3,
"slot_index": 0
"link": 47
}
],
"properties": {
"Node name for S&R": "LayerStyle_Stroke"
},
"widgets_values": [
true,
"normal",
100,
8,
2,
0,
"#DB43A2"
]
"Node name for S&R": "PreviewImage"
}
},
{
"id": 3,
"id": 2,
"type": "LoadImage",
"pos": [
413,
284
310,
390
],
"size": {
"0": 315,
@@ -76,49 +46,7 @@
"name": "IMAGE",
"type": "IMAGE",
"links": [
10
],
"shape": 3,
"slot_index": 0
},
{
"name": "MASK",
"type": "MASK",
"links": [
3
],
"shape": 3,
"slot_index": 1
}
],
"properties": {
"Node name for S&R": "LoadImage"
},
"widgets_values": [
"512x512 (10).png",
"image"
]
},
{
"id": 2,
"type": "LoadImage",
"pos": [
59,
279
],
"size": {
"0": 315,
"1": 314
},
"flags": {},
"order": 1,
"mode": 0,
"outputs": [
{
"name": "IMAGE",
"type": "IMAGE",
"links": [
16
44
],
"shape": 3,
"slot_index": 0
@@ -134,68 +62,140 @@
"Node name for S&R": "LoadImage"
},
"widgets_values": [
"512x512bkgd (7).jpg",
"512x512bk.jpg",
"image"
]
},
{
"id": 4,
"type": "PreviewImage",
"id": 15,
"type": "LoadImage",
"pos": [
1105,
285
660,
399
],
"size": {
"0": 299.7062683105469,
"1": 311.1947937011719
"0": 315,
"1": 314
},
"flags": {},
"order": 3,
"order": 1,
"mode": 0,
"inputs": [
"outputs": [
{
"name": "images",
"name": "IMAGE",
"type": "IMAGE",
"link": 4
"links": [
45
],
"shape": 3,
"slot_index": 0
},
{
"name": "MASK",
"type": "MASK",
"links": [
46
],
"shape": 3,
"slot_index": 1
}
],
"properties": {
"Node name for S&R": "PreviewImage"
}
"Node name for S&R": "LoadImage"
},
"widgets_values": [
"512x512 (14).png",
"image"
]
},
{
"id": 21,
"type": "LayerStyle: Stroke",
"pos": [
1016,
434
],
"size": {
"0": 315,
"1": 242
},
"flags": {},
"order": 2,
"mode": 0,
"inputs": [
{
"name": "background_image",
"type": "IMAGE",
"link": 44
},
{
"name": "layer_image",
"type": "IMAGE",
"link": 45
},
{
"name": "layer_mask",
"type": "MASK",
"link": 46
}
],
"outputs": [
{
"name": "image",
"type": "IMAGE",
"links": [
47
],
"shape": 3,
"slot_index": 0
}
],
"properties": {
"Node name for S&R": "LayerStyle: Stroke"
},
"widgets_values": [
true,
"normal",
100,
0,
8,
0,
"#FF0088"
]
}
],
"links": [
[
3,
3,
44,
2,
0,
21,
0,
"IMAGE"
],
[
45,
15,
0,
21,
1,
"IMAGE"
],
[
46,
15,
1,
21,
2,
"MASK"
],
[
4,
1,
47,
21,
0,
4,
0,
"IMAGE"
],
[
10,
3,
0,
1,
1,
"IMAGE"
],
[
16,
2,
0,
1,
0,
"IMAGE"
]
],
"groups": [],