PSD Layer Compositor
Recomposing a PSD After You've Swapped the Background
- replacement_image
- image
- change_log
- summary
- psd_path
The splitter took your PSD apart; this node puts it back together - with one crucial difference: it lets you swap a layer (or a whole run of layers) for an image you generated, then recomposites everything at the original canvas size using the manifest's positions, opacity, and visibility. It's the workhorse of the "AI background replacement in a real design file" workflow, and the version in the README has grown three replacement modes precisely because real PSDs are messy.
The three replacement modes
- single - replace one layer at
replacement_index(0 = bottom, usually the background) withreplacement_image. The original behavior, and the one that covers a clean PSD. - replace_range - swap a contiguous range
[replacement_index..replacement_end_index]with one image. This is for the messy case where the "background" is actually five stacked layers (gradient, texture, soft shadow, sky, wall) and no single layer is the background.range_fitdecides whether the replacement is sized to the full canvas or to the union bounding box of the replaced layers. - underlay - paste the replacement under all original layers. It's the escape hatch when you genuinely can't pin down which layers are the background; you get the new backdrop behind everything and toggle offending layers' visibility off in the source PSD.
The README's ladder is worth internalizing: try single → detect a range (with PSDBackgroundDetect feeding the indices) → fall back to underlay. Each mode trades automation for reliability.
replacement_fit (stretch / fit / cover / center) and background_color (transparent / white / black / hex) round out the basics - fit letterboxes and cover crops, so pick the one that doesn't distort your generated art.
The fancy part: text recolor
Behind the optional inputs lives real polish: text_recolor_mode can recolor text layers in the output. manual uses text_color for every text layer; auto_contrast picks black or white per layer from the luminance behind it; complement follows the magazine convention (white on dark, black on light). Combined with text_shadow, this keeps captions readable when you've dropped in a wild new background. When output_psd_path is set, recolored text is saved as a clipping PixelLayer above each TypeLayer - so the text stays editable in Photoshop.
The outputs
image is the flat recomposite at original canvas size - the thing you actually wanted. change_log is a detailed run-down of what changed (replaced layers, recolor decisions per layer, shadows, skipped layers, output path); summary is the one-sentence version; psd_path is where the re-exported PSD landed, if you set output_psd_path. That save works in single mode only in v1 - a documented limitation, so don't expect a re-exported PSD from a range swap yet.
Installing it
Part of TrentNodes; install the pack once:
cd ComfyUI/custom_nodes
git clone https://github.com/TrentHunter82/TrentNodes.git
cd TrentNodes
pip install -r requirements.txt
ComfyUI Manager ("Trent Nodes") works too, modulo the known day-one repo-rename quirk that makes Manager sometimes flag the pack as "unsafe" - clone manually if it refuses. Needs psd-tools (in requirements) and the splitter's output folder; no model downloads.
Where people get burned
replacement_indexsemantics - it's the bottom layer that's index 0, matching the splitter. A background that's near the top of the layer panel will not be index 0.- Range indices -
replacement_end_indexis inclusive. Off-by-ones here are the most common PSD complaint. - Hidden layers reappearing -
respect_visibility(default on) skips them; flip it off only if you deliberately want hidden layers composited.
Inputs (17)
| Name | Type | Default | Description |
|---|---|---|---|
| folder_path | STRING | Folder from PSD Layer Splitter (must contain _manifest.json) | |
| replacement_index | INT | 0-1–9999 | Layer index to replace (or start of range). 0 = bottom (usually background). -1 = no replacement. Ignored when replacement_mode = underlay. |
| replacement_end_index | INT | -1-1–9999 | Inclusive end of layer range to replace. -1 = single-layer swap (use replacement_index alone). Only used when replacement_mode = replace_range. |
| replacement_mode | COMBO | single | single = swap one layer at replacement_index. replace_range = swap layers [start..end] with one image. underlay = paste replacement under all original layers (escape hatch for messy PSDs). |
| replacement_fit | COMBO | stretch | How to size the replacement image. stretch = exact fit. fit = preserve AR, letterbox. cover = preserve AR, crop. center = no resize, center |
| range_fit | COMBO | canvas | Target area for replace_range mode. canvas = full PSD canvas (usually what you want). union_bbox = combined bbox of the replaced layers. |
| background_color | STRING | transparent | Canvas backdrop: 'transparent', 'white', 'black', or hex like '#FFFFFF' |
| respect_visibility | BOOLEAN | true | If True, skip layers marked hidden in the original PSD |
| replacement_imageopt | IMAGE | New image to insert at replacement_index | |
| output_psd_pathopt | STRING | PSDComp | Filename or path for the saved .psd. Three modes: - bare prefix ('PSDComp', 'posters/run'): saves to ComfyUI output folder with auto-incrementing counter (PSDComp_00001_.psd, etc.). Subfolders are auto-created. - absolute path ('/abs/path.psd'): saves to that exact path; overwrites if it exists. - empty: skip PSD save (only produce the flat IMAGE output). Original source PSD is never overwritten. Requires replacement_image and replacement_index >= 0. |
| text_recolor_modeopt | COMBO | off | Recolor PSD text layers (kind=='type') in the output. off = leave colors alone. manual = use text_color for every text layer. auto_contrast = pick black or white per layer based on the luminance of pixels behind it. complement = magazine-cover convention: white on darker bg, black on lighter bg, decided per text layer from the bg luminance underneath. Combine with text_shadow for busy bgs. When output_psd_path is set, recolor is also applied to the saved PSD as clipping PixelLayers above each text layer (text stays editable). |
| text_coloropt | STRING | #FFFFFF | Color for text layers when text_recolor_mode=manual. Hex (#RRGGBB), CSS name, or rgb(). |
| auto_contrast_thresholdopt | FLOAT | 0.500–1 | Used when text_recolor_mode=auto_contrast. If avg luminance under the text (0..1) is below this, recolor to white; otherwise to black. |
| text_layer_patternopt | STRING | (?:(?<![A-Za-z])[Tt][Ee][Xx][Tt](?![a-z])|文字|文本|标题|字幕) | Regex matched against layer names. Any layer whose name matches is treated as text and recolored, in addition to real TypeLayers and text-shaped Smart Objects. The default catches 'Text 1', 'Layer 4 - text', 'header_text', 'TextLayer', plus Chinese 文字 / 文本 / 标题 / 字幕 (text / title / subtitle), while excluding 'texture', 'context', 'subtext'. (Layers covering >60% of the canvas are also ignored as a safety net against matched overlays/textures.) Clear the field to recolor TypeLayers only. |
| text_shadowopt | BOOLEAN | false | Add a soft drop shadow behind each recolored text layer. Helps text read on busy or chromatic backgrounds. Applied to flat IMAGE preview and (when output_psd_path is set) inserted as a separate raster layer below each TypeLayer in the saved PSD. No-op when text_recolor_mode=off. |
| flatten_recolored_textopt | BOOLEAN | false | Affects the saved PSD only. OFF (default): keep TypeLayers editable - insert a same-shaped clipping PixelLayer above each recolored TypeLayer to tint it. ON: rasterize recolored TypeLayers in place as flat PixelLayers - the saved PSD shows clean recolored text with no clip-layer indirection, but the text is no longer editable in Photoshop. Useful for clean handoffs when the recipient doesn't need to change the words. Shadow/glow/box decoration layers are unaffected. No-op when text_recolor_mode=off. |
| delete_replaced_layersopt | BOOLEAN | false | Affects the saved PSD only. Applies in replace_range mode to the layers between replacement_index+1 and replacement_end_index (the ones swallowed by the replacement image). OFF (default): those layers stay in the saved PSD but are set to visible=False (recoverable if needed). ON: those layers are removed from the saved PSD entirely - cleaner handoff, smaller file. Only affects the saved file; the source PSD is never modified. No-op in single or underlay replacement_mode. |
Outputs (4)
| Name | Type | Description |
|---|---|---|
| image | IMAGE | Composited image at the original PSD canvas size |
| change_log | STRING | Detailed summary of what changed from the input: replaced layers, text recolors (with chosen colors per layer), shadows added, skipped layers, and output PSD path. |
| summary | STRING | Short sentence-form description of the changes (e.g. "Replaced 4 layers; recolored 4 text layers to white; added shadow to text."). |
| psd_path | STRING | Absolute path of the saved PSD file (after resolution of relative paths / counter increment). Empty string when output_psd_path is blank (no PSD save was requested). |