Rotate Image (BlueBox)
Rotate Image (BlueBox) rotates from the original every time, so three rotations don't blur three times
- image
- rotate_info
- image
- rotate_info
The accumulating-rotation problem
Rotating an image in ComfyUI is not expensive. Rotating it six times, in six nodes, is. Every non-90° rotation resamples with bicubic interpolation and grows the canvas to fit the corners, which get filled black. Chain a few of those - the natural way to do "turn the subject 15° for this pass, then 10° more" - and you get progressively softer pixels, a canvas that keeps swelling, and a black border that a sampler will happily interpret as image content.
Rotate Image (BlueBox) exists to short-circuit that. It doesn't just rotate; it passes a small BLUEBOX_ROTATE_INFO record downstream, and the next rotate node in the chain uses that record to re-rotate from the original baseline instead of from the already-rotated pixels. One resample total, no matter how many nodes are in the chain.
That's the same reasoning as crop-and-stitch: do the geometry once from the source of truth, then put things back.
How it works
Start mode (no rotate_info connected): it records the current image's width and height and the angle you asked for, then rotates. Clockwise is positive, which matches what most people mean by "rotate 10°". Output size is the rotation bounding box, black fill in the corners.
Continue mode (rotate_info connected): the total is previous angle + this angle. Then it does three things in sequence, and this is the part that makes it accurate:
- Reverse-rotate the incoming image by the previous angle, to get back to the original orientation.
- Centre crop-or-pad that back to the exact original width and height, killing the ±1 pixel drift a reverse rotation leaves behind.
- Rotate once, by the total angle, and resize to the analytically computed bounding box -
ceil(w·|cos| + h·|sin|)byceil(w·|sin| + h·|cos|).
So the intermediate nodes get to work on a rotated, correctly-sized image (which is the point - you may be rotating so a tall subject fits a model's preferred aspect), while the final geometry is always derived from the original. Feed the last node in the chain -(total) and you're back to the original frame dimensions, having paid exactly one bicubic pass.
Inputs and outputs
angle(required, INT, −360 to 360) - clockwise degrees. In continue mode this is an increment, not an absolute.image(optional IMAGE) - optional in the schema, mandatory in practice: the node raises an error if it's missing.rotate_info(optional,BLUEBOX_ROTATE_INFO) - wire the previous node's info output here. Unconnected means start mode.
Outputs are image and rotate_info. The info carries the original dimensions and the accumulated angle; the custom type means ComfyUI won't let you wire it anywhere except another rotate node, which is a good guardrail.
Installing
cd ComfyUI/custom_nodes
git clone https://github.com/zhoutingxi/ComfyUI-BlueBox.git ComfyUI-BlueBox
Restart ComfyUI; it lives under BlueBox/experimental. Manager search term is ComfyUI-BlueBox. No pip installs - the repo's requirements.txt is empty, and this node uses only torch, numpy and Pillow, all of which ComfyUI already has. Like everything else in the pack, the browser-facing parts want WebGL and IndexedDB (Chrome/Edge), though this particular node needs neither.
Common issues
"My rotated image came out wrong when I chained it." Continue mode assumes the image arriving at the node is already at the previous angle. If you feed it the original image into a continue node, it reverse-rotates something that was never rotated. Wire the rotated output through, or don't pass rotate_info at all.
Black corners. expand plus black fill, every time - that's the geometry, not a bug. If the image is going into a sampler next, either crop back in first or mask the corners, because a diffusion model will cheerfully generate content into a black wedge.
Transparent PNGs go dark at the edges. RGBA input has its alpha multiplied into the RGB before rotation, so semi-transparent pixels darken instead of staying transparent. Composite first, or start from a flattened RGB image.
Only the first image survives a batch. The node takes image[0], so a four-image batch comes out as one rotated frame - fine for stills, wrong for anything you're treating as a sequence.
Inputs (3)
| Name | Type | Default | Description |
|---|---|---|---|
| angle | INT | 0-360–360 | — |
| imageopt | IMAGE | — | |
| rotate_infoopt | BLUEBOX_ROTATE_INFO | — |
Outputs (2)
| Name | Type | Description |
|---|---|---|
| image | IMAGE | — |
| rotate_info | BLUEBOX_ROTATE_INFO | — |