Images to RGB (Swwan)
The boring node that saves you from a channel-count error
- images
- IMAGE
What it's for
One input, one output, no widgets. Images to RGB takes an IMAGE and hands back an IMAGE with exactly three channels, values inside 0–1.
You reach for it in two situations. The first is alpha. An RGBA tensor floating around your graph will work in some nodes and quietly misbehave in others - and if you hand it to a saver that isn't alpha-aware you can end up with a fourth channel interpreted as something it isn't. Flattening to RGB makes the handoff unambiguous. The second is range. If a previous node did maths on your pixels and pushed values past 1.0 (or below 0), the node folds the range back before conversion instead of letting it clip into a blown-out mess.
The pack pairs it with ColorImage (Swwan), which is the node that makes solid-colour images and converts colour parameters - RGB conversion is the read side of that pair, and the pack's own CPU example workflow chains a colour image → resize → grid → Images to RGB → save.
How it works
The conversion is a PIL round-trip, deliberately matching the behaviour of WAS Node Suite's Images to RGB without importing WAS. The mechanism, in order:
- If the tensor's max is above 1.001 or its min is below -0.001, the whole batch is divided by the maximum and clamped to 0–1. That's the dynamic-range fold - it preserves relative values, but it scales the entire batch by one number, so a single hot frame dims its neighbours.
- The tensor is split into planes (it handles 3-channel batches, and 4+ channel inputs, and single-plane input).
- Each plane goes through PIL's RGB conversion at 8 bits.
- The result is stacked back into an
IMAGEtensor.
Step 3 is the honest caveat: this is a lossy round-trip through 8-bit, not a zero-copy channel slice. If your image is already 3-channel and in range, the node is effectively a no-op with a quantisation step attached. Use it deliberately, not habitually in the middle of a float pipeline.
Empty input raises rather than returning an empty batch, which is at least a clear failure.
Inputs and outputs
That's genuinely it: images in, IMAGE out. The single output is unnamed in the schema beyond its type, so wire it to whatever consumes an image - a saver, a VAE Encode, the next utility node.
There's a design decision worth naming if you're coming from other packs: this is not a channel splitter. It doesn't preserve alpha, it doesn't give you a mask, and it won't tell you what it changed. For that, the pack has Split Image Channels and Merge Image Channels, and the RGBA family (RGBA Safe Pre, RGBA Safe Post) for workflows that need real alpha preserved end to end.
Install
cd ComfyUI/custom_nodes
git clone https://github.com/aining2022/ComfyUI_Swwan
cd ComfyUI_Swwan
python -m pip install -r requirements.txt
Restart ComfyUI, refresh the browser, search Swwan. Requirements are numpy, Pillow, opencv-python, scipy and scikit-image; torch comes from your existing environment. This node needs nothing beyond Pillow and torch, so it also works on a CPU-only install - as does the pack's model-free example workflow, which is a decent smoke test that the install actually took.
Common issues
Everything looks slightly flatter after it. You ran a float image through an 8-bit conversion. If you didn't need an RGB guarantee, drop the node.
Output suddenly darker than the input. One frame in the batch exceeded 1.0, so the entire batch got divided by that maximum. Normalise or clamp upstream instead of relying on the fold.
Nodes still complain about channel count. Check what you're feeding - some custom nodes expect exactly [B,H,W,3] and this gives you that, so a remaining complaint is usually about batch dimensions or dtype rather than channels. The pack keeps dtype handling internal (fp16 gets promoted where it matters), so a dtype mismatch usually points somewhere else in the graph.
Inputs (1)
| Name | Type | Default | Description |
|---|---|---|---|
| images | IMAGE | — |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| IMAGE | IMAGE | — |