Add GradientOverlay, ColorOverlay nodes and add invalid mask input judgment.

This commit is contained in:
chflame163
2024-01-21 22:42:01 +08:00
committed by GitHub
parent 35ef662ae1
commit 4ec4a9672c
21 changed files with 825 additions and 64 deletions
+61 -7
View File
@@ -7,6 +7,7 @@ The completed nodes are as follows, and further work is in progress.
[中文说明点这里](./README_CN.MD)
## Update
* Add GradientOverlay and ColorOverlay nodes. Add invalid mask input judgment and ignore it when invalid mask is input.
* 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.
* OuterGlow node has undergone significant modifications by adding options for **_brightness_**, **_light_color_**, and **_glow_color_**.
@@ -21,8 +22,9 @@ The completed nodes are as follows, and further work is in progress.
* Commit DropShadow node.
# LayerStyle
![image](image/layerstyle_nodes.png)
### DropShadow:
### DropShadow
Generate shadow
![image](image/drop_shadow_example.png)
@@ -41,7 +43,7 @@ Node options:
* blur: Shadow blur level.
* shadow_color<sup>4</sup>: Shadow color.
### OuterGlow:
### OuterGlow
Generate outer glow
![image](image/outer_glow_example.png)
@@ -59,7 +61,7 @@ Node options:
* light_color<sup>4</sup>: Center part color of glow.
* glow_color<sup>4</sup>: Edge part color of glow.
### InnerShadow:
### InnerShadow
Generate inner shadow
![image](image/inner_shadow_example.png)
@@ -77,7 +79,7 @@ Node options:
* blur: Shadow blur level.
* shadow_color<sup>4</sup>: Shadow color.
### InnerGlow:
### InnerGlow
Generate inner glow
![image](image/inner_glow_example.png)
@@ -96,7 +98,7 @@ Node options:
* glow_color<sup>4</sup>: Edge part color of glow.
### Stroke:
### Stroke
Generate a stroke of layer。
![image](image/stroke_example.png)
@@ -112,6 +114,37 @@ Node options:
* stroke_width: Stroke width.
* stroke_color<sup>4</sup>: Stroke color, described in hexadecimal RGB format.
### GradientOverlay
Generate gradient overlay
![image](image/gradient_overlay_example.png)
Node options:
* background_image<sup>1</sup>: The background image.
* layer_image<sup>1</sup>: Layer image for composite.
* layer_mask<sup>1,2</sup>: Mask for layer_image.
* invert_mask: Whether to reverse the mask.
* blend_mode<sup>3</sup>: Blending mode of gradient.
* opacity: Opacity of stroke.
* start_color: Color at the beginning of the gradient.
* start_alpha: Transparency at the beginning of the gradient.
* end_color: Color at the end of the gradient.
* end_alpha: Transparency at the end of the gradient.
* angle: Gradient rotation angle.
### ColorOverlay
Generate color overlay
![image](image/color_overlay_example.png)
Node options:
![image](image/color_overlay_node.png)
* background_image<sup>1</sup>: The background image.
* layer_image<sup>1</sup>: Layer image for composite.
* layer_mask<sup>1,2</sup>: Mask for layer_image.
* invert_mask: Whether to reverse the mask.
* blend_mode<sup>3</sup>: Blending mode of color.
* opacity: Opacity of stroke.
* color: Color of overlay.
#### 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.。
@@ -123,6 +156,7 @@ Node options:
<sup>4</sup> The RGB color described by hexadecimal RGB format, like '#FA3D86'.
# LayerMask
![image](image/layermask_nodes.png)
### MaskPreview:
Preview the input mask
@@ -134,6 +168,7 @@ Invert the mask
# LayerUtility
![image](image/layerutility_nodes.png)
### ImageBlend:
Composit layer image and background image, multiple blend modes are available for option, and transparency can be set.
@@ -169,6 +204,7 @@ Output Type:
* string
# LayerFilter
![image](image/layerfilter_nodes.png)
### MotionBlur:
Make the image motion blur
@@ -183,8 +219,26 @@ image Some JSON workflow files in the workflow directory, that is example for Co
## The following tasks are in the planned list
* Color Overlay
* Gradient Overlay
* LayerUtility:
imageblend advance
color image
gradient image
* LayerMask:
text mask
gradient mask
mask grow&blur
mask subtract
mask combine
mask diffrent
mask gradient
mask softedge
* LayerFilter:
bulr
emboss
contour
findedge
## How to install
+82 -27
View File
@@ -1,10 +1,11 @@
# ComfyUI Layer Style:
# ComfyUI Layer Style
ComfyUI插件,通过一组节点实现仿照Adobe Photoshop的图层样式。
已完成的节点如下,后续工作进行中。
![image](image/title.png)
## 更新说明:
## 更新说明:
* 添加GradientOverlay,ColorOverlay节点。增加无效mask输入判断,当输入无效mask时将其忽略。
* 添加InnerGlow, InnerShadow, MotionBlur节点。
* 所有已完成的节点重新命名,节点分为4组:LayerStyle, LayerMask, LayerUtility, LayerFilter。因为重新命名,包含旧版节点的工作流需手动替换新版节点。
* OuterGlow节点修改,增加亮度、灯光颜色、辉光颜色选项。
@@ -18,12 +19,13 @@ ComfyUI
* 首个节点DropShadow提交。
# LayerStyle
![image](image/layerstyle_nodes.png)
### DropShadow:
### DropShadow
生成阴影。
![image](image/drop_shadow_example.png)
节点选项说明:
节点选项说明:
![image](image/drop_shadow_node.png)
* background_image<sup>1</sup>: 背景图像。
* layer_image<sup>1</sup>: 用于合成的层图像。
@@ -34,14 +36,14 @@ ComfyUI
* distance_x: 阴影的水平方向偏移量。
* distance_y: 阴影的垂直方向偏移量。
* grow: 阴影扩张幅度。
* blur:阴影模糊程度。
* blur:阴影模糊程度。
* shadow_color<sup>4</sup>: 阴影颜色。
### OuterGlow:
### OuterGlow
生成外发光。
![image](image/outer_glow_example.png)
节点选项说明:
节点选项说明:
![image](image/outer_glow_node.png)
* background_image<sup>1</sup>: 背景图像。
* layer_image<sup>1</sup>: 用于合成的层图像。
@@ -51,15 +53,15 @@ ComfyUI
* opacity: 发光的不透明度。
* brightness: 发光亮度。
* glow_range: 发光范围。
* blur:发光模糊程度。
* blur:发光模糊程度。
* light_color<sup>4</sup>: 发光中心颜色。
* glow_colo<sup>4</sup>: 辉光外围颜色。
### InnerShadow:
### InnerShadow
生成内阴影。
![image](image/inner_shadow_example.png)
节点选项说明:
节点选项说明:
![image](image/inner_shadow_node.png)
* background_image<sup>1</sup>: 背景图像。
* layer_image<sup>1</sup>: 用于合成的层图像。
@@ -70,14 +72,14 @@ ComfyUI
* distance_x: 阴影的水平方向偏移量。
* distance_y: 阴影的垂直方向偏移量。
* grow: 阴影扩张幅度。
* blur:阴影模糊程度。
* blur:阴影模糊程度。
* shadow_color<sup>4</sup>: 阴影颜色。
### InnerGlow:
### InnerGlow
生成内发光。
![image](image/inner_glow_example.png)
节点选项说明:
节点选项说明:
![image](image/inner_glow_node.png)
* background_image<sup>1</sup>: 背景图像。
* layer_image<sup>1</sup>: 用于合成的层图像。
@@ -87,15 +89,15 @@ ComfyUI
* opacity: 发光的不透明度。
* brightness: 发光亮度。
* glow_range: 发光范围。
* blur:发光模糊程度。
* blur:发光模糊程度。
* light_color<sup>4</sup>: 发光中心颜色。
* glow_colo<sup>4</sup>: 辉光外围颜色。
### Stroke:
### Stroke
生成描边。
![image](image/stroke_example.png)
节点选项说明:
节点选项说明:
![image](image/stroke_node.png)
* background_image<sup>1</sup>: 背景图像。
* layer_image<sup>1</sup>: 用于合成的层图像。
@@ -103,18 +105,51 @@ ComfyUI
* invert_mask: 是否反转遮罩。
* blend_mode<sup>3</sup>: 描边的混合模式。
* opacity: 不透明度。
* stroke_grow<sup></sup>: 描边扩张/收缩幅度,正值是扩张,负值是收缩。
* stroke_width<sup></sup>:描边宽度。
* stroke_grow: 描边扩张/收缩幅度,正值是扩张,负值是收缩。
* stroke_width: 描边宽度。
* stroke_color<sup>4</sup>: 描边颜色。
### GradientOverlay
渐变覆盖
![image](image/gradient_overlay_example.png)
#### 节点选项注解:
节点选项说明:
![image](image/gradient_overlay_node.png)
* background_image<sup>1</sup>: 背景图像。
* layer_image<sup>1</sup>: 用于合成的层图像。
* layer_mask<sup>1,2</sup>: 层图像的遮罩。
* invert_mask: 是否反转遮罩。
* blend_mode<sup>3</sup>: 描边的混合模式。
* opacity: 不透明度。
* start_color: 渐变开始端的颜色。
* start_alpha: 渐变开始端的透明度。
* end_color: 渐变结束端的颜色。
* end_alpha: 渐变结束端的透明度。
* angle: 渐变旋转角度。
### ColorOverlay
颜色覆盖
![image](image/color_overlay_example.png)
节点选项说明:
![image](image/color_overlay_node.png)
* background_image<sup>1</sup>: 背景图像。
* layer_image<sup>1</sup>: 用于合成的层图像。
* layer_mask<sup>1,2</sup>: 层图像的遮罩。
* invert_mask: 是否反转遮罩。
* blend_mode<sup>3</sup>: 描边的混合模式。
* opacity: 不透明度。
* color: 覆盖的颜色。
#### 节点选项注解:
<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
![image](image/layermask_nodes.png)
### MaskPreview:
预览mask
@@ -125,12 +160,13 @@ mask
![image](image/mask_invert_node.png)
# LayerUtility
![image](image/layerutility_nodes.png)
### ImageBlend:
用于合成图层,提供多种混合模式供选择,可设置透明度。
![image](image/image_blend_example.png)
节点选项说明:
节点选项说明:
![image](image/image_blend_node.png)
* background_image<sup>1</sup>: 背景图像。
* layer_image<sup>1</sup>: 用于合成的层图像。
@@ -143,7 +179,7 @@ mask
调整图像不透明度。
![image](image/image_opacity_example.png)
节点选项说明:
节点选项说明:
* image: 图像输入,支持RGB和RGBA输入。
* mask: 遮罩输入。
* invert_mask: 是否反转遮罩。
@@ -154,31 +190,50 @@ mask
改自[mtb nodes](https://github.com/melMass/comfy_mtb)的web extensions。
![image](image/color_picker.png)
节点选项说明:
节点选项说明:
* mode: 输出格式,可选十六进制(HEX)或十进制(DEC)。
输出:
输出:
* string
# LayerFilter
![image](image/layerfilter_nodes.png)
### MotionBlur:
运动模糊。
![image](image/motion_blur_example.png)
节点选项说明:
节点选项说明:
* angle: 模糊角度。
* blur: 模糊大小。
## 使用示例:
## 使用示例:
在workflow目录下有json格式的工作流示例文件。
## 以下工作在计划列表中
* Color Overlay
* Gradient Overlay
* LayerUtility:
imageblend advance
color image
gradient image
* LayerMask:
text mask
gradient mask
mask grow&blur
mask subtract
mask combine
mask diffrent
mask gradient
mask softedge
* LayerFilter:
bulr
emboss
contour
findedge
## 安装方法:
Binary file not shown.

After

Width:  |  Height:  |  Size: 541 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 88 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 508 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 128 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 158 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 159 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 165 KiB

BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 372 KiB

After

Width:  |  Height:  |  Size: 376 KiB

+66
View File
@@ -0,0 +1,66 @@
from .imagefunc import *
class ColorOverlay:
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}), # 透明度
"color": ("STRING", {"default": "#FFBF30"}), # 渐变开始颜色
},
"optional": {
"layer_mask": ("MASK",), #
}
}
RETURN_TYPES = ("IMAGE",)
RETURN_NAMES = ("image",)
FUNCTION = 'color_overlay'
CATEGORY = '😺dzNodes/LayerStyle'
OUTPUT_NODE = True
def color_overlay(self, background_image, layer_image,
invert_mask, blend_mode, opacity, color,
layer_mask=None
):
# preprocess
_canvas = tensor2pil(background_image).convert('RGB')
_layer = tensor2pil(layer_image)
if _layer.mode == 'RGBA':
_mask = tensor2pil(layer_image).convert('RGBA').split()[-1]
else:
_mask = Image.new('L', _layer.size, 'white')
_layer = _layer.convert('RGB')
if layer_mask is not None:
if invert_mask:
layer_mask = 1 - layer_mask
_mask = mask2image(layer_mask).convert('L')
if _mask.size != _layer.size:
_mask = Image.new('L', _layer.size, 'white')
log('Warning: mask mismatch, droped!')
_color = Image.new('RGB', size=_layer.size, color=color)
# 合成layer
_comp = chop_image(_layer, _color, blend_mode, opacity)
_canvas.paste(_comp, mask=_mask)
ret_image = _canvas
log('ColorOverlay Processed.')
return (pil2tensor(ret_image),)
NODE_CLASS_MAPPINGS = {
"LayerStyle: ColorOverlay": ColorOverlay
}
NODE_DISPLAY_NAME_MAPPINGS = {
"LayerStyle: ColorOverlay": "LayerStyle: ColorOverlay"
}
+13 -5
View File
@@ -38,16 +38,24 @@ class DropShadow:
layer_mask=None
):
distance_x = -distance_x
distance_y = -distance_y
# preprocess
_canvas = tensor2pil(background_image).convert('RGB')
_layer = tensor2pil(layer_image).convert('RGB')
_mask = tensor2pil(layer_image).convert('RGBA').split()[-1]
# 处理mask
_layer = tensor2pil(layer_image)
if _layer.mode == 'RGBA':
_mask = tensor2pil(layer_image).convert('RGBA').split()[-1]
else:
_mask = Image.new('L', _layer.size, 'white')
_layer = _layer.convert('RGB')
if layer_mask is not None:
if invert_mask:
layer_mask = 1 - layer_mask
_mask = mask2image(layer_mask).convert('L')
if _mask.size != _layer.size:
_mask = Image.new('L', _layer.size, 'white')
log('Warning: mask mismatch, droped!')
distance_x = -distance_x
distance_y = -distance_y
if distance_x != 0 or distance_y != 0:
__mask = shift_image(_mask, distance_x, distance_y) # 位移
shadow_mask = expand_mask(image2mask(__mask), grow, blur) #扩张,模糊
+79
View File
@@ -0,0 +1,79 @@
from .imagefunc import *
class GradientOverlay:
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}), # 透明度
"start_color": ("STRING", {"default": "#FFBF30"}), # 渐变开始颜色
"start_alpha": ("INT", {"default": 255, "min": 0, "max": 255, "step": 1}),
"end_color": ("STRING", {"default": "#FE0000"}), # 渐变结束颜色
"end_alpha": ("INT", {"default": 255, "min": 0, "max": 255, "step": 1}),
"angle": ("INT", {"default": 0, "min": -180, "max": 180, "step": 1}), # 渐变角度
},
"optional": {
"layer_mask": ("MASK",), #
}
}
RETURN_TYPES = ("IMAGE",)
RETURN_NAMES = ("image",)
FUNCTION = 'gradient_overlay'
CATEGORY = '😺dzNodes/LayerStyle'
OUTPUT_NODE = True
def gradient_overlay(self, background_image, layer_image,
invert_mask, blend_mode, opacity,
start_color, start_alpha, end_color, end_alpha, angle,
layer_mask=None
):
# preprocess
_canvas = tensor2pil(background_image).convert('RGB')
_layer = tensor2pil(layer_image)
if _layer.mode == 'RGBA':
_mask = tensor2pil(layer_image).convert('RGBA').split()[-1]
else:
_mask = Image.new('L', _layer.size, 'white')
_layer = _layer.convert('RGB')
if layer_mask is not None:
if invert_mask:
layer_mask = 1 - layer_mask
_mask = mask2image(layer_mask).convert('L')
if _mask.size != _layer.size:
_mask = Image.new('L', _layer.size, 'white')
log('Warning: mask mismatch, droped!')
_gradient = gradint(start_color, end_color, _layer.width, _layer.height, float(angle))
# 合成layer
_comp = chop_image(_layer, _gradient, blend_mode, opacity)
if start_alpha < 255 or end_alpha < 255:
#
start_color = RGB_to_Hex((start_alpha, start_alpha, start_alpha))
end_color = RGB_to_Hex((end_alpha, end_alpha, end_alpha))
comp_alpha = gradint(start_color, end_color, _layer.width, _layer.height, float(angle))
comp_alpha = ImageChops.invert(comp_alpha).convert('L')
_comp.paste(_layer, comp_alpha)
_canvas.paste(_comp, mask=_mask)
ret_image = _canvas
log('GradientOverlay Processed.')
return (pil2tensor(ret_image),)
NODE_CLASS_MAPPINGS = {
"LayerStyle: GradientOverlay": GradientOverlay
}
NODE_DISPLAY_NAME_MAPPINGS = {
"LayerStyle: GradientOverlay": "LayerStyle: GradientOverlay"
}
+70 -12
View File
@@ -6,7 +6,7 @@ import torch
import scipy.ndimage
import cv2
from typing import Union, List
from PIL import Image, ImageFilter, ImageChops
from PIL import Image, ImageFilter, ImageChops, ImageDraw
def log(message):
name = 'LayerStyle'
@@ -119,9 +119,70 @@ def motion_blur(image:Image, angle:int, blur:int) -> Image:
ret_image = cv22pil(blurred)
return ret_image
def direction_blur(image:Image, angle:int, blur:int, color:str) -> Image:
def __rotate_expand(image:Image, angle:float, SSAA:int=0) -> Image:
images = pil2tensor(image)
expand = "true"
height, width = images[0, :, :, 0].shape
ret_image = image
def rotate_tensor(tensor):
resize_sampler = Image.LANCZOS
rotate_sampler = Image.BICUBIC
if SSAA > 1:
img = tensor.tensor_to_image()
img_us_scaled = img.resize((width * SSAA, height * SSAA), resize_sampler)
img_rotated = img_us_scaled.rotate(angle, rotate_sampler, expand == "true", fillcolor=(0, 0, 0, 0))
img_down_scaled = img_rotated.resize((img_rotated.width // SSAA, img_rotated.height // SSAA), resize_sampler)
result = img_down_scaled.image_to_tensor()
else:
img = tensor.tensor_to_image()
img_rotated = img.rotate(angle, rotate_sampler, expand == "true", fillcolor=(0, 0, 0, 0))
result = img_rotated.image_to_tensor()
return result
if angle == 0.0 or angle == 360.0:
return tensor2pil(images)
else:
rotated_tensor = torch.stack([rotate_tensor(images[i]) for i in range(len(images))])
return tensor2pil(rotated_tensor).convert('RGB')
def image_rotate_extend_with_alpha(image:Image, alpha:Image, angle:float, SSAA:int=0) -> tuple:
_image = __rotate_expand(image.convert('RGB'), angle, SSAA)
_alpha = __rotate_expand(alpha.convert('RGB'), angle, SSAA)
R, G, B = _image.split()
A = _alpha.convert('L')
ret_image = Image.merge('RGBA', (R, G, B, A))
return (_image, _alpha, ret_image)
def create_gradient(start_color_inhex:str, end_color_inhex:str, width:int, height:int) -> Image:
start_color = Hex_to_RGB(start_color_inhex)
end_color = Hex_to_RGB(end_color_inhex)
ret_image = Image.new("RGB", (width, height), start_color)
draw = ImageDraw.Draw(ret_image)
for i in range(height):
R = int(start_color[0] * (height - i) / height + end_color[0] * i / height)
G = int(start_color[1] * (height - i) / height + end_color[1] * i / height)
B = int(start_color[2] * (height - i) / height + end_color[2] * i / height)
color = (R, G, B)
draw.line((0, i, width, i), fill=color)
return ret_image
def gradint(start_color_inhex:str, end_color_inhex:str, width:int, height:int, angle:float, ) -> Image:
radius = int((width + height) / 4)
g = create_gradient(start_color_inhex, end_color_inhex, radius, radius)
_canvas = Image.new('RGB', size=(radius, radius*3), color=start_color_inhex)
top = Image.new('RGB', size=(radius, radius), color=start_color_inhex)
bottom = Image.new('RGB', size=(radius, radius),color=end_color_inhex)
_canvas.paste(top, box=(0, 0, radius, radius))
_canvas.paste(g, box=(0, radius, radius, radius * 2))
_canvas.paste(bottom,box=(0, radius * 2, radius, radius * 3))
_canvas = _canvas.resize((radius * 3, radius * 3))
_canvas = __rotate_expand(_canvas,angle)
center = int(_canvas.width / 2)
_x = int(width / 3)
_y = int(height / 3)
ret_image = _canvas.crop((center - _x, center - _y, center + _x, center + _y))
ret_image = ret_image.resize((width, height))
return ret_image
'''Mask Functions'''
@@ -180,18 +241,15 @@ 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))
def step_color(start_color_inhex:str, end_color_inhex:str, total_step:int, step:int) -> str: # 按当前步数在总步数中的位置返回比例颜色
start_color = tuple(Hex_to_RGB(start_color_inhex))
end_color = tuple(Hex_to_RGB(end_color_inhex))
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 = (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 RGB_to_Hex(ret_color)
+10 -3
View File
@@ -38,14 +38,21 @@ class InnerGlow:
layer_mask=None
):
# preprocess
_canvas = tensor2pil(background_image).convert('RGB')
_layer = tensor2pil(layer_image).convert('RGB')
_mask = tensor2pil(layer_image).convert('RGBA').split()[-1]
# 处理mask
_layer = tensor2pil(layer_image)
if _layer.mode == 'RGBA':
_mask = tensor2pil(layer_image).convert('RGBA').split()[-1]
else:
_mask = Image.new('L', _layer.size, 'white')
_layer = _layer.convert('RGB')
if layer_mask is not None:
if invert_mask:
layer_mask = 1 - layer_mask
_mask = mask2image(layer_mask).convert('L')
if _mask.size != _layer.size:
_mask = Image.new('L', _layer.size, 'white')
log('Warning: mask mismatch, droped!')
blur_factor = blur / 20.0
grow = glow_range
+13 -5
View File
@@ -39,16 +39,24 @@ class InnerShadow:
layer_mask=None
):
distance_x = -distance_x
distance_y = -distance_y
# preprocess
_canvas = tensor2pil(background_image).convert('RGB')
_layer = tensor2pil(layer_image).convert('RGB')
_mask = tensor2pil(layer_image).convert('RGBA').split()[-1]
# 处理mask
_layer = tensor2pil(layer_image)
if _layer.mode == 'RGBA':
_mask = tensor2pil(layer_image).convert('RGBA').split()[-1]
else:
_mask = Image.new('L', _layer.size, 'white')
_layer = _layer.convert('RGB')
if layer_mask is not None:
if invert_mask:
layer_mask = 1 - layer_mask
_mask = mask2image(layer_mask).convert('L')
if _mask.size != _layer.size:
_mask = Image.new('L', _layer.size, 'white')
log('Warning: mask mismatch, droped!')
distance_x = -distance_x
distance_y = -distance_y
if distance_x != 0 or distance_y != 0:
__mask = shift_image(_mask, distance_x, distance_y) # 位移
shadow_mask = expand_mask(image2mask(__mask), grow, blur) #扩张,模糊
+11 -3
View File
@@ -38,14 +38,22 @@ class OuterGlow:
layer_mask=None
):
# preprocess
_canvas = tensor2pil(background_image).convert('RGB')
_layer = tensor2pil(layer_image).convert('RGB')
_mask = tensor2pil(layer_image).convert('RGBA').split()[-1]
# 处理mask
_layer = tensor2pil(layer_image)
if _layer.mode == 'RGBA':
_mask = tensor2pil(layer_image).convert('RGBA').split()[-1]
else:
_mask = Image.new('L', _layer.size, 'white')
_layer = _layer.convert('RGB')
if layer_mask is not None:
if invert_mask:
layer_mask = 1 - layer_mask
_mask = mask2image(layer_mask).convert('L')
if _mask.size != _layer.size:
_mask = Image.new('L', _layer.size, 'white')
log('Warning: mask mismatch, droped!')
blur_factor = blur / 20.0
grow = glow_range
for x in range(brightness):
+10 -2
View File
@@ -37,13 +37,21 @@ class Stroke:
layer_mask=None
):
# preprocess
_canvas = tensor2pil(background_image).convert('RGB')
_layer = tensor2pil(layer_image).convert('RGB')
_mask = tensor2pil(layer_image).convert('RGBA').split()[-1]
_layer = tensor2pil(layer_image)
if _layer.mode == 'RGBA':
_mask = tensor2pil(layer_image).convert('RGBA').split()[-1]
else:
_mask = Image.new('L', _layer.size, 'white')
_layer = _layer.convert('RGB')
if layer_mask is not None:
if invert_mask:
layer_mask = 1 - layer_mask
_mask = mask2image(layer_mask).convert('L')
if _mask.size != _layer.size:
_mask = Image.new('L', _layer.size, 'white')
log('Warning: mask mismatch, droped!')
grow_offset = int(stroke_width / 2)
inner_stroke = stroke_grow - grow_offset
+203
View File
@@ -0,0 +1,203 @@
{
"last_node_id": 25,
"last_link_id": 61,
"nodes": [
{
"id": 15,
"type": "LoadImage",
"pos": [
659,
386
],
"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": [
60
],
"shape": 3,
"slot_index": 1
}
],
"properties": {
"Node name for S&R": "LoadImage"
},
"widgets_values": [
"512x512 (14).png",
"image"
]
},
{
"id": 2,
"type": "LoadImage",
"pos": [
307,
382
],
"size": {
"0": 315,
"1": 314
},
"flags": {},
"order": 1,
"mode": 0,
"outputs": [
{
"name": "IMAGE",
"type": "IMAGE",
"links": [
58
],
"shape": 3,
"slot_index": 0
},
{
"name": "MASK",
"type": "MASK",
"links": [],
"shape": 3,
"slot_index": 1
}
],
"properties": {
"Node name for S&R": "LoadImage"
},
"widgets_values": [
"512x512bk.jpg",
"image"
]
},
{
"id": 24,
"type": "LayerStyle: ColorOverlay",
"pos": [
1008,
440
],
"size": {
"0": 315,
"1": 170
},
"flags": {},
"order": 2,
"mode": 0,
"inputs": [
{
"name": "background_image",
"type": "IMAGE",
"link": 58
},
{
"name": "layer_image",
"type": "IMAGE",
"link": 59
},
{
"name": "layer_mask",
"type": "MASK",
"link": 60
}
],
"outputs": [
{
"name": "image",
"type": "IMAGE",
"links": [
61
],
"shape": 3,
"slot_index": 0
}
],
"properties": {
"Node name for S&R": "LayerStyle: ColorOverlay"
},
"widgets_values": [
true,
"multply",
66,
"#FFBF30"
]
},
{
"id": 4,
"type": "PreviewImage",
"pos": [
1358,
386
],
"size": {
"0": 310.00006103515625,
"1": 308.33331298828125
},
"flags": {},
"order": 3,
"mode": 0,
"inputs": [
{
"name": "images",
"type": "IMAGE",
"link": 61
}
],
"properties": {
"Node name for S&R": "PreviewImage"
}
}
],
"links": [
[
58,
2,
0,
24,
0,
"IMAGE"
],
[
59,
15,
0,
24,
1,
"IMAGE"
],
[
60,
15,
1,
24,
2,
"MASK"
],
[
61,
24,
0,
4,
0,
"IMAGE"
]
],
"groups": [],
"config": {},
"extra": {},
"version": 0.4
}
+207
View File
@@ -0,0 +1,207 @@
{
"last_node_id": 29,
"last_link_id": 66,
"nodes": [
{
"id": 4,
"type": "PreviewImage",
"pos": [
1358,
386
],
"size": {
"0": 310.00006103515625,
"1": 308.33331298828125
},
"flags": {},
"order": 3,
"mode": 0,
"inputs": [
{
"name": "images",
"type": "IMAGE",
"link": 66
}
],
"properties": {
"Node name for S&R": "PreviewImage"
}
},
{
"id": 2,
"type": "LoadImage",
"pos": [
307,
382
],
"size": {
"0": 315,
"1": 314
},
"flags": {},
"order": 0,
"mode": 0,
"outputs": [
{
"name": "IMAGE",
"type": "IMAGE",
"links": [
62
],
"shape": 3,
"slot_index": 0
},
{
"name": "MASK",
"type": "MASK",
"links": [],
"shape": 3,
"slot_index": 1
}
],
"properties": {
"Node name for S&R": "LoadImage"
},
"widgets_values": [
"512x512bk.jpg",
"image"
]
},
{
"id": 15,
"type": "LoadImage",
"pos": [
659,
386
],
"size": {
"0": 315,
"1": 314
},
"flags": {},
"order": 1,
"mode": 0,
"outputs": [
{
"name": "IMAGE",
"type": "IMAGE",
"links": [
63
],
"shape": 3,
"slot_index": 0
},
{
"name": "MASK",
"type": "MASK",
"links": [
64
],
"shape": 3,
"slot_index": 1
}
],
"properties": {
"Node name for S&R": "LoadImage"
},
"widgets_values": [
"512x512 (14).png",
"image"
]
},
{
"id": 27,
"type": "LayerStyle: GradientOverlay",
"pos": [
1015,
408
],
"size": {
"0": 315,
"1": 266
},
"flags": {},
"order": 2,
"mode": 0,
"inputs": [
{
"name": "background_image",
"type": "IMAGE",
"link": 62
},
{
"name": "layer_image",
"type": "IMAGE",
"link": 63
},
{
"name": "layer_mask",
"type": "MASK",
"link": 64
}
],
"outputs": [
{
"name": "image",
"type": "IMAGE",
"links": [
66
],
"shape": 3,
"slot_index": 0
}
],
"properties": {
"Node name for S&R": "LayerStyle: GradientOverlay"
},
"widgets_values": [
true,
"normal",
100,
"#FFBF30",
60,
"#FE0000",
255,
0
]
}
],
"links": [
[
62,
2,
0,
27,
0,
"IMAGE"
],
[
63,
15,
0,
27,
1,
"IMAGE"
],
[
64,
15,
1,
27,
2,
"MASK"
],
[
66,
27,
0,
4,
0,
"IMAGE"
]
],
"groups": [],
"config": {},
"extra": {},
"version": 0.4
}