# Documentation - Class name: ImageCompositeAbsolute - Category: image/composite - Output node: False ImageCompositeAbsolute 节点用于通过精确定位两个输入图像来创建复合图像。它根据给定的坐标、容器尺寸和指定的合成方法来处理这些图像的精确放置和混合,从而实现复杂的视觉布局创作。 # Input types ## Required - images_a - 要在容器内合成的第一个图像。它在复合图像的图层顺序和视觉效果中起着关键作用。 - Comfy dtype: IMAGE - Python dtype: numpy.ndarray - images_b - 要在容器内合成的第二个图像,为最终复合图像增添复杂性和深度。 - Comfy dtype: IMAGE - Python dtype: numpy.ndarray - images_a_x - 第一个图像在容器内左上角的 x 坐标,定义其水平位置。 - Comfy dtype: INT - Python dtype: int - images_a_y - 第一个图像在容器内左上角的 y 坐标,定义其垂直位置。 - Comfy dtype: INT - Python dtype: int - images_b_x - 第二个图像在容器内左上角的 x 坐标,定义其水平位置。 - Comfy dtype: INT - Python dtype: int - images_b_y - 第二个图像在容器内左上角的 y 坐标,定义其垂直位置。 - Comfy dtype: INT - Python dtype: int - container_width - 指定用于合成输入图像的容器宽度。它决定了合成的水平边界。 - Comfy dtype: INT - Python dtype: int - container_height - 指定用于合成输入图像的容器高度。它决定了合成的垂直边界。 - Comfy dtype: INT - Python dtype: int - background - 确定将哪个输入图像(images_a 或 images_b)用作复合图像的背景。这个选择会影响最终图像的图层和视觉效果。 - Comfy dtype: COMBO[STRING] - Python dtype: str - method - 指定要使用的合成方法,影响图像在容器内的混合方式。 - Comfy dtype: COMBO[STRING] - Python dtype: str # Output types - image - 根据指定参数和方法合成输入图像后得到的结果图像。 - Comfy dtype: IMAGE - Python dtype: numpy.ndarray # Usage tips - Infra type: CPU - Common nodes: - [PreviewImage](https://github.com/comfyanonymous/ComfyUI/blob/master/nodes/image.py) - VAEEncode - [ImageScale](https://github.com/comfyanonymous/ComfyUI/blob/master/nodes/image.py) # Source code python class ImageCompositeAbsolute: @classmethod def INPUT_TYPES(s): return { "required": { "images_a": ("IMAGE",), "images_b": ("IMAGE",), "images_a_x": ("INT", {"default": 0, "min": 0, "max": MAX_RESOLUTION, "step": 1}), "images_a_y": ("INT", {"default": 0, "min": 0, "max": MAX_RESOLUTION, "step": 1}), "images_b_x": ("INT", {"default": 0, "min": 0, "max": MAX_RESOLUTION, "step": 1}), "images_b_y": ("INT", {"default": 0, "min": 0, "max": MAX_RESOLUTION, "step": 1}), "container_width": ("INT", {"default": 512, "min": 16, "max": MAX_RESOLUTION, "step": 1}), "container_height": ("INT", {"default": 512, "min": 16, "max": MAX_RESOLUTION, "step": 1}), "background": (["images_a", "images_b"],), "method": (["normal", "multiply", "screen", "overlay", "soft_light"],) } } RETURN_TYPES = ("IMAGE",) FUNCTION = "composite" CATEGORY = "image/composite" def composite(self, images_a, images_b, images_a_x, images_a_y, images_b_x, images_b_y, container_width, container_height, background, method): images_a = images_a.clone().movedim(-1,1) images_b = images_b.clone().movedim(-1,1) if background == "images_a": results = [] canvas = torch.zeros((images_a.shape[0], 4, container_height, container_width), dtype=torch.float32, device="cpu") canvas[:, :, images_a_y:images_a_y + images_a.shape[2], images_a_x:images_a_x + images_a.shape[3]] = images_a images_b = torch.nn.functional.pad(images_b, (images_b_x, container_width - images_b_x - images_b.shape[3], images_b_y, container_height - images_b_y - images_b.shape[2]), "constant", 0) images_b = images_b[:, :, :container_height, :container_width] results.append(canvas) results.append(images_b) else: results = [] canvas = torch.zeros((images_b.shape[0], 4, container_height, container_width), dtype=torch.float32, device="cpu") canvas[:, :, images_b_y:images_b_y + images_b.shape[2], images_b_x:images_b_x + images_b.shape[3]] = images_b images_a = torch.nn.functional.pad(images_a, (images_a_x, container_width - images_a_x - images_a.shape[3], images_a_y, container_height - images_a_y - images_a.shape[2]), "constant", 0) images_a = images_a[:, :, :container_height, :container_width] results.append(canvas) results.append(images_a) if method == "normal": return (self.normal(results[0], results[1]).movedim(1,-1),) elif method == "multiply": return (self.multiply(results[0], results[1]).movedim(1,-1),) elif method == "screen": return (self.screen(results[0], results[1]).movedim(1,-1),) elif method == "overlay": return (self.overlay(results[0], results[1]).movedim(1,-1),) elif method == "soft_light": return (self.soft_light(results[0], results[1]).movedim(1,-1),) def normal(self, bg, fg): out = torch.where(fg[:,:4] == 0, bg, fg[:,:4]) out[:, 3:4] = 1 - (1 - fg[:, 3:4]) * (1 - bg[:, 3:4]) return out def multiply(self, bg, fg): out = fg * bg out[:, 3:4] = 1 - (1 - fg[:, 3:4]) * (1 - bg[:, 3:4]) return out def screen(self, bg, fg): out = bg + fg - (bg * fg) out[:, 3:4] = 1 - (1 - fg[:, 3:4]) * (1 - bg[:, 3:4]) return out def overlay(self, bg, fg): def f(bg, fg): return torch.where(bg <= 0.5, 2 * bg * fg, 1 - 2 * (1 - bg) * (1 - fg)) out = fg.clone() out[:, :3] = f(bg[:, :3], fg[:, :3]) out[:, 3:4] = 1 - (1 - fg[:, 3:4]) * (1 - bg[:, 3:4]) return out def soft_light(self, bg, fg): def f(bg, fg): return torch.where(fg <= 0.5, bg - (1 - 2 * fg) * bg * (1 - bg), bg + (2 * fg - 1) * (self.d(bg) - bg)) def d(x): return torch.where(x <= 0.25, ((16 * x - 12) * x + 4) * x, torch.sqrt(x)) self.d = d out = fg.clone() out[:, :3] = f(bg[:, :3], fg[:, :3]) out[:, 3:4] = 1 - (1 - fg[:, 3:4]) * (1 - bg[:, 3:4]) return out ```