Skip to content

Commit 31486d7

Browse files
committed
add the ImageTransitionLeftToRight node.
1 parent ca49c09 commit 31486d7

File tree

3 files changed

+102
-4
lines changed

3 files changed

+102
-4
lines changed

README.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,10 @@ Enhanced the official UpscaleImageWithModel node by adding a judge. If the input
102102
This node is designed to composite a watermark into the destination image. It can select the position of the watermark, resize the watermark according to the input ratio, and add a margin to the watermark.
103103

104104
## ImageTransition
105-
This node is designed to generate a transition image between two images. It can generate a transition image between two images.
105+
This node is designed to generate a transition image between two images. The first image gradually fades out while the second image simultaneously appears, creating a smooth transition effect.
106+
107+
## ImageTransitionLeftToRight
108+
This node is designed to generate a transition image between two images. The first image gradually slides to the right while the second image simultaneously appears from the left, creating a smooth transition effect.
106109

107110
## TorchCompileModelAdvanced
108111
This node enables model compilation using torch.compile. It extends ComfyUI's original torch compile node by adding compile mode options and a toggle switch.

py/nodes_video.py

Lines changed: 97 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,10 +55,105 @@ def adjust_frames(self, images: torch.Tensor, duration: float, fps: float, remov
5555
new_images = torch.cat([new_images, images[-1].unsqueeze(0).repeat(repeat_count, 1, 1, 1)], dim=0)
5656
return (new_images, len(new_images), fps)
5757

58+
class ImageTransitionLeftToRight:
59+
def __init__(self):
60+
pass
61+
62+
@classmethod
63+
def INPUT_TYPES(cls):
64+
return {"required":{
65+
"before_image": ("IMAGE",),
66+
"after_image": ("IMAGE",),
67+
"duration": ("FLOAT", {"default": 5.0, "min": 0.1, "max": 60.0, "step": 0.1}),
68+
"fps": ("FLOAT", {"default": 24.0, "min": 1.0, "max": 120.0, "step": 1.0}),
69+
},
70+
}
71+
72+
RETURN_TYPES = ("IMAGE", "FLOAT", "FLOAT")
73+
RETURN_NAMES = ("images", "duration", "fps")
74+
FUNCTION = "create_transition"
75+
CATEGORY = "utils"
76+
77+
def create_transition(self, before_image: torch.Tensor, after_image: torch.Tensor, duration: float, fps: float):
78+
print(f"before_image: {before_image.shape}, after_image: {after_image.shape}")
79+
# 确保输入是单张图片,如果是批次则取第一张
80+
if len(before_image.shape) == 4 and before_image.shape[0] > 1:
81+
before_image = before_image[0:1]
82+
if len(after_image.shape) == 4 and after_image.shape[0] > 1:
83+
after_image = after_image[0:1]
84+
85+
# 获取目标尺寸(前图的尺寸)
86+
_, target_width = before_image.shape[1:3]
87+
88+
89+
adjusted_after = self.check_and_resizee_size(before_image, after_image)
90+
91+
# 计算总帧数
92+
total_frames = int(duration * fps)
93+
94+
# 创建过渡帧
95+
frames = []
96+
97+
for i in range(total_frames):
98+
# 计算当前过渡位置 (0.0 到 1.0)
99+
progress = i / (total_frames - 1) if total_frames > 1 else 1.0
100+
101+
# 计算过渡线的x坐标
102+
transition_x = int(target_width * progress)
103+
104+
# 创建新帧
105+
new_frame = torch.zeros_like(before_image)
106+
107+
# 从左到右过渡:左侧显示后图,右侧显示前图
108+
# 先填充整个前图
109+
new_frame[0] = before_image[0]
110+
111+
# 然后在左侧填充后图(覆盖前图)
112+
if transition_x > 0:
113+
new_frame[0, :, :transition_x,:] = adjusted_after[0, :, :transition_x, :]
114+
115+
frames.append(new_frame)
116+
117+
# 合并所有帧
118+
result = torch.cat(frames, dim=0)
119+
120+
return (result, duration, fps)
121+
122+
def check_and_resizee_size(self, before_image, after_image):
123+
# 获取目标尺寸(前图的尺寸)
124+
target_height, target_width = before_image.shape[1:3]
125+
126+
# 获取后图的原始尺寸
127+
after_height, after_width = after_image.shape[1:3]
128+
adjusted_after = after_image
129+
if target_height != after_height or target_width != after_width:
130+
# 保持比例调整后图尺寸
131+
# 先计算缩放比例
132+
scale = min(target_height / after_height, target_width / after_width)
133+
new_height = int(after_height * scale)
134+
new_width = int(after_width * scale)
135+
136+
# 缩放后图
137+
resized_after = torch.nn.functional.interpolate(
138+
after_image.movedim(-1, 1), size=(new_height, new_width), mode='bicubic', align_corners=False
139+
).movedim(1, -1).clamp(0.0, 1.0)
140+
# 创建空白画布(与前图尺寸相同)
141+
adjusted_after = torch.zeros_like(before_image)
142+
143+
# 计算居中位置
144+
y_offset = (target_height - new_height) // 2
145+
x_offset = (target_width - new_width) // 2
146+
147+
# 将缩放后的图像放置在画布中央
148+
adjusted_after[:,:,:,:] = resized_after[0, y_offset:y_offset+new_height, x_offset:x_offset+new_width,:]
149+
return adjusted_after
150+
58151
NODE_CLASS_MAPPINGS = {
59-
"FrameAdjuster": FrameAdjuster
152+
"FrameAdjuster": FrameAdjuster,
153+
"ImageTransitionLeftToRight": ImageTransitionLeftToRight
60154
}
61155

62156
NODE_DISPLAY_NAME_MAPPINGS = {
63-
"FrameAdjuster": "Frame Adjuster"
157+
"FrameAdjuster": "Frame Adjuster",
158+
"ImageTransitionLeftToRight": "Image Transition Left to Right"
64159
}

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
[project]
22
name = "comfyui-utils-nodes"
33
description = "Nodes:LoadImageWithSwitch, ImageBatchOneOrMore, ModifyTextGender, GenderControlOutput, ImageCompositeMaskedWithSwitch, ImageCompositeMaskedOneByOne, ColorCorrectOfUtils, SplitMask, MaskFastGrow, CheckpointLoaderSimpleWithSwitch, ImageResizeTo8x, MatchImageRatioToPreset, UpscaleImageWithModelIfNeed, MaskFromFaceModel, MaskCoverFourCorners, DetectorForNSFW, DeepfaceAnalyzeFaceAttributes etc."
4-
version = "1.2.7"
4+
version = "1.2.8"
55
license = { file = "LICENSE" }
66
dependencies = []
77

0 commit comments

Comments
 (0)