Nodes/ComfyUI-EsesImageTransform/Eses Image Transform
ComfyUI Node

Eses Image Transform

The one node that flips, spins, zooms, tiles, and masks in a single shot

By quasiblob·Created about a year ago·Updated about a year ago· 14
Eses Image Transform
  • image
  • mask
  • IMAGE
  • MASK
  • info
flip_xfalse
flip_yfalse
offset_x0
offset_y0
zoom_factor1.000
rotation_angle0.00
local_scale_x1.00
local_scale_y1.00
tiling_mode
max_tiling_grid_size3
tiling_pixel_overlap4
apply_mask_to_rgb_imagefalse
invert_mask_inputfalse
invert_mask_outputfalse
resample_filter
fill_color0,0,0

ComfyUI's built-in image nodes are maddeningly coarse. There's a flip, a rotate that only steps in 90° increments, and a scale - and the moment you want to rotate an image by 14.7° while sliding it around and zooming, you're chaining four nodes together and still not getting the mask to follow along. Eses Image Transform is the "why isn't this just one node" answer. It treats your image like a card you can move, rotate, squash, and repeat inside its frame - and it transforms an optional mask with it, so alpha always stays glued to the pixels.

It's the only node in quasiblob's pack, and the author's stated reason for existing is that he doesn't like node packs. No model files, no new dependencies, no VRAM pressure: the whole thing is roughly 18 KB of Pillow calls running on CPU.

How it works

Mechanically it's a Pillow perspective transform with the matrix math done in NumPy. Your torch image and mask get converted to PIL on the CPU, flips are applied first as plain mirror/flip operations, then a transform matrix built from rotation, zoom × local scale, and offset is handed to Pillow. Everything runs on CPU, so it never touches your VRAM.

The interesting bit is tiling. When you zoom out below 1.0 with tiling on, it doesn't tile the canvas naively - it builds a 3×-oversized canvas of repeated tiles, applies the transform at zoom 1.0, then crops back to the original size. That oversize-and-crop trick is why the pattern stays seamless at the edges instead of showing cutoff strips. tiling_pixel_overlap pads each tile so seams don't show, and max_tiling_grid_size (rounded to the nearest odd number so it centers symmetrically) caps how many repeats it bothers drawing.

The inputs that matter

All 16 sliders and toggles are "required," which reads scary, but most have sane defaults - the node just doesn't have an "advanced" tier. The ones you'll actually touch:

  • rotation_angle, zoom_factor, offset_x/offset_y - the core transform. Zoom below 1.0 to pull back; offsets are raw pixels (±2048, so plenty for big canvases), not normalized.
  • local_scale_x/local_scale_y - non-uniform scale applied before rotation. Squash something to 0.6 wide and it stays squashed through a rotation, which is handy for faking perspective.
  • tiling_mode plus the grid size and overlap - only does anything when zoom ≠ 1.0.
  • fill_color - what the exposed canvas gets filled with. Accepts 255,128,0 (RGB), 0,255,0,128 (RGBA), or hex.
  • resample_filter - bicubic (default), bilinear, or nearest. Nearest is your friend when you're scaling a mask.
  • The three mask toggles: invert_mask_input flips the mask before transforming, invert_mask_output after, and apply_mask_to_rgb_image uses the transformed mask as the output image's alpha channel.

Outputs

Three outputs: IMAGE (always RGBA), MASK (the transformed grayscale mask), and info - a plain string summarizing what you applied ("Rot: 14.7, Zoom: 0.850, ..."), handy to pipe into a Show Text node or store as metadata.

Installing it

Easiest via ComfyUI Manager - search the pack title "ComfyUI-EsesImageTransform" and hit install. Or the manual route:

cd ComfyUI/custom_nodes
git clone https://github.com/quasiblob/ComfyUI-EsesImageTransform.git

Restart ComfyUI and the node appears under Eses Nodes/Image. There's no requirements.txt and no model download; PyTorch and Pillow both ship with ComfyUI. It genuinely cannot break your environment - which is more than most of the packs in this ecosystem can claim.

Gotchas and troubleshooting

  • The image output is RGBA, composited onto fill_color. Exposed canvas isn't transparent by default - it's filled black. If you actually want transparency to survive, use a 4-channel fill like 0,0,0,0.
  • It's CPU-only. Fine for 1024–2048 px images; a big tiled job with bicubic resampling will feel sluggish. That's the price of zero dependencies.
  • With no image connected it returns a blank 64×64 image and an info string that reads "No valid input." - that's your cue you forgot to wire the image.
  • There's no community signal to lean on. This pack has essentially zero Reddit footprint and no search impressions; don't go looking for tutorials, because there aren't any. The README and the source are short and clear, and they're all you get.
  • The license isn't MIT. It's a custom "personal use" license: free to use and modify for yourself, but no rebranding, no code reuse, no bundling. Fine for a workflow; a deal-breaker if you were hoping to lift the tiling math into your own pack - ask the author first.

If all you need is a rotate-and-flip for a quick upscale pass, use the core nodes. The moment you want arbitrary-angle rotation with a mask that stays glued to the pixels, or seamless tiling for a background, this is the one to reach for.

CategoryEses Nodes/Image

Inputs (18)

NameTypeDefaultDescription
flip_xBOOLEANfalse
flip_yBOOLEANfalse
offset_xFLOAT0-2048–2048
offset_yFLOAT0-2048–2048
zoom_factorFLOAT1.0000.01–10
rotation_angleFLOAT0.00-360–360
local_scale_xFLOAT1.000.01–10
local_scale_yFLOAT1.000.01–10
tiling_modeCOMBO2 options: Off, On
max_tiling_grid_sizeINT31–111
tiling_pixel_overlapINT40–64
apply_mask_to_rgb_imageBOOLEANfalse
invert_mask_inputBOOLEANfalse
invert_mask_outputBOOLEANfalse
resample_filterCOMBO3 options: bicubic, bilinear, nearest
fill_colorSTRING0,0,0
imageoptIMAGE
maskoptMASK

Outputs (3)

NameTypeDescription
IMAGEIMAGE
MASKMASK
infoINFO