LayerMask: MaskGradient¶
Documentation¶
- Class name:
LayerMask: MaskGradient
- Category:
😺dzNodes/LayerMask
- Output node:
False
The MaskGradient
node is designed to apply gradient effects to masks, enhancing visual aesthetics or highlighting specific areas. It leverages gradient parameters to dynamically adjust the appearance of input masks, offering a versatile tool for image manipulation and layer styling within graphical interfaces.
Input types¶
Required¶
mask
- The mask input represents the target image mask to which the gradient effect will be applied. It is crucial for defining the area of effect and the base for gradient application.
- Comfy dtype:
MASK
- Python dtype:
torch.Tensor
invert_mask
- This parameter determines whether the input mask should be inverted before applying the gradient effect, allowing for flexibility in targeting either the masked area or its inverse.
- Comfy dtype:
BOOLEAN
- Python dtype:
bool
gradient_side
- Specifies the side of the mask where the gradient effect begins, enabling directional control over the gradient application.
- Comfy dtype:
COMBO[STRING]
- Python dtype:
str
gradient_scale
- Controls the scale of the gradient effect, affecting how the gradient transitions across the mask area.
- Comfy dtype:
INT
- Python dtype:
float
gradient_offset
- Adjusts the starting point of the gradient effect within the mask, offering additional customization for the gradient's positioning.
- Comfy dtype:
INT
- Python dtype:
float
opacity
- Sets the opacity level of the gradient effect, allowing for fine-tuning of the visual impact on the mask.
- Comfy dtype:
INT
- Python dtype:
float
Optional¶
Output types¶
mask
- Comfy dtype:
MASK
- The output is a tensor containing the modified mask(s) with the applied gradient effect, showcasing the visual transformation.
- Python dtype:
torch.Tensor
- Comfy dtype:
Usage tips¶
- Infra type:
GPU
- Common nodes: unknown
Source code¶
class MaskGradient:
def __init__(self):
pass
@classmethod
def INPUT_TYPES(self):
side = ['top', 'bottom', 'left', 'right']
return {
"required": {
"mask": ("MASK",),
"invert_mask": ("BOOLEAN", {"default": True}), # 反转mask
"gradient_side": (side,),
"gradient_scale": ("INT", {"default": 100, "min": 1, "max": 9999, "step": 1}),
"gradient_offset": ("INT", {"default": 0, "min": -9999, "max": 9999, "step": 1}),
"opacity": ("INT", {"default": 100, "min": 0, "max": 100, "step": 1}),
},
"optional": {
}
}
RETURN_TYPES = ("MASK",)
RETURN_NAMES = ("mask",)
FUNCTION = 'mask_gradient'
CATEGORY = '😺dzNodes/LayerMask'
def mask_gradient(self, mask, invert_mask, gradient_side, gradient_scale, gradient_offset, opacity, ):
if mask.dim() == 2:
mask = torch.unsqueeze(mask, 0)
l_masks = []
ret_masks = []
for m in mask:
if invert_mask:
m = 1 - m
l_masks.append(tensor2pil(torch.unsqueeze(m, 0)).convert('L'))
for i in range(len(l_masks)):
_mask = l_masks[i]
_canvas = copy.copy(_mask)
width = _mask.width
height = _mask.height
_gradient = gradient('#000000', '#FFFFFF',
1024, 1024, 0)
# (box_x, box_y, box_width, box_height) = min_bounding_rect(_mask)
(box_x, box_y, box_width, box_height) = mask_area(_mask)
log(f"{NODE_NAME}: Box detected. x={box_x},y={box_y},width={box_width},height={box_height}")
if box_width < 1 or box_height < 1:
log(f"Error: {NODE_NAME} skipped, because the mask is does'nt have valid area", message_type='error')
return (mask,)
if gradient_side == 'top':
boxsize = (width, box_height)
_gradient = _gradient.transpose(Image.FLIP_TOP_BOTTOM)
_gradient = _gradient.resize(boxsize)
_black = Image.new('RGB', size = boxsize, color = 'black')
if gradient_scale != 100:
_box = Image.new('RGB', size = boxsize, color = 'black')
_gradient = _gradient.resize((width, int(box_height * gradient_scale / 100)))
_box.paste(_gradient, box = (0, 0))
_gradient = _box
if gradient_offset != 0:
_box = Image.new('RGB', size = boxsize, color = 'black')
_boxwhite = Image.new('RGB', size = boxsize, color = 'white')
_box.paste(_gradient, box=(0, gradient_offset))
_box.paste(_boxwhite, box = (0, gradient_offset - _box.height))
_gradient = _box
if gradient_offset > box_height:
_gradient = Image.new('RGB', size = boxsize, color = 'white')
_canvas.paste(_black, box = (0, box_y), mask = _gradient.convert('L'))
elif gradient_side == 'bottom':
boxsize = (width, box_height)
_gradient = _gradient.resize((width, box_height))
_black = Image.new('RGB', size = boxsize, color = 'black')
if gradient_scale != 100:
_box = Image.new('RGB', size = boxsize, color = 'black')
_gradient = _gradient.resize((width, int(box_height * gradient_scale / 100)))
_box.paste(_gradient, box = (0, box_height - _gradient.height))
_gradient = _box
if gradient_offset != 0:
_box = Image.new('RGB', size = boxsize, color = 'black')
_boxwhite = Image.new('RGB', size = boxsize, color = 'white')
_box.paste(_gradient, box=(0, gradient_offset))
_box.paste(_boxwhite, box = (0, gradient_offset + _box.height))
_gradient = _box
if gradient_offset < -box_height:
_gradient = Image.new('RGB', size=boxsize, color='white')
_canvas.paste(_black, box = (0, box_y + 1), mask = _gradient.convert('L'))
elif gradient_side == 'left':
boxsize = (box_width, height)
_gradient = _gradient.transpose(Image.ROTATE_270)
_gradient = _gradient.resize(boxsize)
_black = Image.new('RGB', size = boxsize, color = 'black')
if gradient_scale != 100:
_box = Image.new('RGB', size = boxsize, color = 'black')
_gradient = _gradient.resize((int(box_width * gradient_scale / 100), height))
_box.paste(_gradient, box = (0, 0))
_gradient = _box
if gradient_offset != 0:
_box = Image.new('RGB', size = boxsize, color = 'black')
_boxwhite = Image.new('RGB', size = boxsize, color = 'white')
_box.paste(_gradient, box=(gradient_offset, 0))
_box.paste(_boxwhite, box = (gradient_offset - _box.width, 0))
_gradient = _box
if gradient_offset > box_width:
_gradient = Image.new('RGB', size=boxsize, color='white')
_canvas.paste(_black, box = (box_x, 0), mask = _gradient.convert('L'))
elif gradient_side == 'right':
boxsize = (box_width, height)
_gradient = _gradient.transpose(Image.ROTATE_90)
_gradient = _gradient.resize(boxsize)
_black = Image.new('RGB', size = boxsize, color = 'black')
if gradient_scale != 100:
_box = Image.new('RGB', size = boxsize, color = 'black')
_gradient = _gradient.resize((int(box_width * gradient_scale / 100), height))
_box.paste(_gradient, box = (box_width - _gradient.width, 0))
_gradient = _box
if gradient_offset != 0:
_box = Image.new('RGB', size = boxsize, color = 'black')
_boxwhite = Image.new('RGB', size = boxsize, color = 'white')
_box.paste(_gradient, box=(gradient_offset, 0))
_box.paste(_boxwhite, box = (gradient_offset + _box.width, 0))
_gradient = _box
if gradient_offset < -box_width:
_gradient = Image.new('RGB', size=boxsize, color='white')
_canvas.paste(_black, box = (box_x + 1, 0), mask = _gradient.convert('L'))
# opacity
if opacity < 100:
_canvas = chop_image(_mask, _canvas, 'normal', opacity)
ret_masks.append(image2mask(_canvas))
log(f"{NODE_NAME} Processed {len(ret_masks)} mask(s).", message_type='finish')
return (torch.cat(ret_masks, dim=0),)