Nodes/comfyui-ps-normal-layer-composite/PS Normal Layer Composite (RGBA)
ComfyUI Node

PS Normal Layer Composite (RGBA)

Stack two transparent images like Photoshop, without leaving ComfyUI

By Doki21yy·Created 3 months ago·Updated 3 months ago· 0
PS Normal Layer Composite (RGBA)
  • bottom_image
  • top_image
  • bottom_alpha
  • top_alpha
  • rgba_image
  • rgb_preview
  • alpha
  • comfy_transparency_mask
top_x0
top_y0
top_opacity1.00
canvas_modebottom_size
canvas_width512
canvas_height512
mask_modecomfy_transparency_mask

You've got a transparent subject - from LayerDiffusion, a Qwen layer decomposition, or a BiRefNet cutout - and you want it sitting on top of a background, offset, at 70% opacity, with the edges staying clean. ComfyUI core can paste one image on another, but it doesn't do proper alpha blending on the way, and the result is a hard-edged rectangle or a fake-looking composite. This node does the thing you'd normally open Photoshop for: a normal-mode layer stack, straight from the graph.

It's from a tiny, no-dependency pack by Doki21yy - two nodes total, no models to download, one real job each. This one composites; the sibling (SaveTransparentPNG) saves.

How it works

The math is the classic "source-over" straight-alpha blend you know from every image editor. The node multiplies the top layer's alpha by top_opacity, then combines: final alpha is top alpha plus bottom alpha scaled by what's left uncovered. Colors are blended in premultiplied space and divided back out, which is exactly how Photoshop's Normal mode behaves - soft edges stay soft instead of picking up a dark halo.

The part that actually bites people is the mask convention. ComfyUI's built-in IMAGE is RGB-only, so transparency travels separately as a MASK - and ComfyUI's masks come in two contradictory flavors. LoadImage's mask output is white where transparent (an inverted alpha, the engine's quirk). Mask-edit nodes usually output white = selected/opaque. This node's mask_mode maps to those two worlds:

  • comfy_transparency_mask (default) - treats the MASK as 1 = transparent. Correct for LoadImage masks.
  • alpha_mask - treats the MASK as straight alpha, 1 = opaque. Use it when your mask came from a selection tool.

The inputs that matter

You set maybe half of these:

  • bottom_image / top_image - the stack, bottom first. Optionally wire bottom_alpha / top_alpha (MASK) if your images arrived as RGB.
  • top_x / top_y - where the top layer sits, in pixels. Negative values move it up/left; you're not limited to inside the canvas.
  • top_opacity - 0 to 1, default 1. Your "layer opacity" slider.
  • canvas_mode - bottom_size (default), top_size, union_size (bounds of both), or custom_size with canvas_width / canvas_height. The canvas is the one thing you'll flip if your top layer hangs off the bottom edge.

Outputs

rgba_image is a real 4-channel IMAGE with the alpha baked back in - the one to save. rgb_preview is a flattened preview for screenshots, and you get two masks: alpha (1 = opaque) and comfy_transparency_mask (1 = transparent) if you want to feed the result into something that expects either convention.

Install

No dependencies, no model files - the pack only uses numpy, torch, and PIL, all of which ship with ComfyUI already. Install via ComfyUI Manager (search "comfyui-ps-normal-layer-composite") or manually:

cd ComfyUI/custom_nodes
git clone https://github.com/Doki21yy/comfyui-ps-normal-layer-composite.git

Restart ComfyUI. That's the whole install.

Where people get burned

  • Everything composites opaque. You fed a LoadImage but didn't wire its MASK output to bottom_alpha/top_alpha. LoadImage gives you RGB in one socket and alpha in another; this node can't see the second one unless you connect it.
  • Inverted transparency - white where it should be clear, or the reverse. That's the mask_mode trap above; flip it and it fixes itself.
  • Soft or bleeding edges. When a canvas mode resizes a layer it uses bilinear interpolation on the alpha too, so semi-transparent pixels stay semi-transparent. That's a feature - it's what keeps cutouts from looking pasted-on.

Worth knowing: it's a brand-new, single-commit pack with zero track record, so don't build a production pipeline on it without a quick sanity check. But for a two-node job like this, it's refreshingly simple - and it does the one thing ComfyUI core refuses to.

Categoryimage/composite

Inputs (11)

NameTypeDefaultDescription
bottom_imageIMAGE
top_imageIMAGE
top_xINT0-16384–16384
top_yINT0-16384–16384
top_opacityFLOAT1.000–1
canvas_modeCOMBObottom_size4 options: bottom_size, top_size, union_size, custom_size
canvas_widthINT5121–16384
canvas_heightINT5121–16384
mask_modeCOMBOcomfy_transparency_mask2 options: comfy_transparency_mask, alpha_mask
bottom_alphaoptMASK
top_alphaoptMASK

Outputs (4)

NameTypeDescription
rgba_imageIMAGE
rgb_previewIMAGE
alphaMASK
comfy_transparency_maskMASK