diff --git a/README.MD b/README.MD index fb30542..55afa70 100644 --- a/README.MD +++ b/README.MD @@ -12,6 +12,7 @@ Nodes are divided into four groups according to their functions: LayerStyle, Lay [中文说明点这里](./README_CN.MD) ## Update +* Commit [ChannelShake](#ChannelShake) node, that is filter, can produce channel dislocation effect similar like Tiktok logo. * Commit [MaskGradient](#MaskGradient) node, can create a gradient in the mask. * Commit [GetColorTone](#GetColorTone) node, can obtain the main color or average color of the image. Commit [MaskGrow](#MaskGrow) and [MaskEdgeShrink](#MaskEdgeShrink) nodes. @@ -386,6 +387,16 @@ This node allows any type of input. ![image](image/layerfilter_nodes.png) +### ChannelShake +Channel misalignment. similar to the effect of Tiktok logo. +![image](image/channel_shake_example.png) + +Node options: +![image](image/channel_shake_node.png) +* distance: Distance of channel separation. +* angle: Angle of channel separation. +* mode: Channel shift arrangement order. + ### MotionBlur Make the image motion blur ![image](image/motion_blur_example.png) diff --git a/image/channel_shake_example.png b/image/channel_shake_example.png new file mode 100644 index 0000000..51412e2 Binary files /dev/null and b/image/channel_shake_example.png differ diff --git a/image/channel_shake_node.png b/image/channel_shake_node.png new file mode 100644 index 0000000..e7a2391 Binary files /dev/null and b/image/channel_shake_node.png differ diff --git a/py/channel_shake.py b/py/channel_shake.py new file mode 100644 index 0000000..35784b8 --- /dev/null +++ b/py/channel_shake.py @@ -0,0 +1,60 @@ +import math + +from .imagefunc import * + +class ChannelShake: + + def __init__(self): + pass + + @classmethod + def INPUT_TYPES(self): + channel_mode = ['RGB', 'RBG', 'BGR', 'BRG', 'GBR', 'GRB'] + return { + "required": { + "image": ("IMAGE", ), # + "distance": ("INT", {"default": 20, "min": 1, "max": 999, "step": 1}), # 距离 + "angle": ("FLOAT", {"default": 40, "min": -360, "max": 360, "step": 0.01}), # 角度 + "mode": (channel_mode,), # 模式 + }, + "optional": { + } + } + + RETURN_TYPES = ("IMAGE",) + RETURN_NAMES = ("image",) + FUNCTION = 'channel_shake' + CATEGORY = '😺dzNodes/LayerFilter' + OUTPUT_NODE = True + + def channel_shake(self, image, distance, angle, mode, ): + + _canvas = tensor2pil(image).convert('RGB') + R, G, B = _canvas.split() + x = int(math.cos(angle) * distance) + y = int(math.sin(angle) * distance) + if mode.startswith('R'): + R = shift_image(R.convert('RGB'), -x, -y).convert('L') + if mode.startswith('G'): + G = shift_image(G.convert('RGB'), -x, -y).convert('L') + if mode.startswith('B'): + B = shift_image(B.convert('RGB'), -x, -y).convert('L') + if mode.endswith('R'): + R = shift_image(R.convert('RGB'), x, y).convert('L') + if mode.endswith('G'): + G = shift_image(G.convert('RGB'), x, y).convert('L') + if mode.endswith('B'): + B = shift_image(B.convert('RGB'), x, y).convert('L') + + ret_image = Image.merge('RGB', [R, G, B]) + log('ChannelShake Processed.') + + return (pil2tensor(ret_image),) + +NODE_CLASS_MAPPINGS = { + "LayerFilter: ChannelShake": ChannelShake +} + +NODE_DISPLAY_NAME_MAPPINGS = { + "LayerFilter: ChannelShake": "LayerFilter: ChannelShake" +} \ No newline at end of file diff --git a/py/imagefunc.py b/py/imagefunc.py index bb28468..34e1686 100644 --- a/py/imagefunc.py +++ b/py/imagefunc.py @@ -153,11 +153,9 @@ def __rotate_expand(image:Image, angle:float, SSAA:int=0, method:str="lanczos") 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() result = pil2tensor(img_down_scaled) else: img_rotated = img.rotate(angle, rotate_sampler, expand == "true", fillcolor=(0, 0, 0, 0)) - # result = img_rotated.image_to_tensor() result = pil2tensor(img_rotated) return result