Load Image To Canvas
A mini canvas editor that lives inside your workflow
- IMAGE
- MASK
- ORIGINAL IMAGE
Sometimes you don't want to compute crop coordinates - you want to look at the image and drag it into place. Load Image To Canvas is the hands-on member of the ComfyUI-ResizeToCanvasSize pack: it loads an image from disk and lets you composite it onto a canvas interactively, with a live preview, drag-to-reposition, scroll-to-zoom, flip controls, and all six padding fills. Where the other two nodes in the pack are automatic pipeline stages, this one is deliberately manual. User interaction is the point.
It's the node you reach for when you're prepping a base image - say a real photo you're about to inpaint or a starting frame for a composition - and you want it on a specific canvas, positioned by eye rather than by math. The README frames it as a "manual, intentional starting node," and that's exactly what it is.
How it works
The transform order is right there in the source: load → apply flips → apply zoom_x / zoom_y → place the image centre at offset × canvas → composite over the padding_fill → compute the mask. A few details worth knowing:
- EXIF orientation is applied on load, so your phone photos stop coming in sideways. Small touch, very welcome.
- The aspect-ratio lock stores
locked_ratio = zoom_x / zoom_y. When locked,zoom_yis derived fromzoom_xand that ratio, so the proportions you set while unlocked are preserved. - The file list comes from ComfyUI's
input/folder - the node scans it for PNG/JPG/WebP/BMP/GIF. The node'sIS_CHANGEDuses the file's mtime, so re-running the queue picks up a changed file on disk.
The interactive bits (rotary zoom dials, Fit Width/Height buttons, the Swap W↔H button, drag and scroll) all just drive the ordinary numeric fields underneath - zoom_x, zoom_y, offset_x, offset_y, lock_aspect_ratio, canvas_width, canvas_height.
The inputs and outputs that matter
image- a file picker limited to what's in yourinput/folder (or upload straight from the node).canvas_width/canvas_height- target canvas, 1–8192 px. The Swap button toggles between portrait and landscape in one click.offset_x/offset_y- position;0.5is centred. Drag the preview and these update live.zoom_x/zoom_y- zoom multipliers,1.0= 100%. Independent when the lock is off, which is how you distort on purpose.padding_fillandcustom_color_hex/noise_seed- same six options as the rest of the pack.
Three outputs: IMAGE (RGBA), MASK, and ORIGINAL IMAGE - a raw passthrough of the loaded file with zero transforms, which is handy if you want the untouched version further downstream.
The subtle part: the mask changes meaning
The MASK output is context-aware, and this is where people get confused. When the image doesn't fully cover the canvas, the mask is canvas-space - white where the image sits, black in the padding. When the image fully covers or crops into the canvas, the mask switches to source-image-space - white marking which source pixels were sampled. So the mask isn't always canvas-sized, and its interpretation flips depending on coverage. invert_mask flips white/black in both cases. If you're feeding this into an inpainting setup, check which state you're in before you trust the mask.
Install and gotchas
Same as the pack: ComfyUI Manager search "ComfyUI-ResizeToCanvasSize", or git clone into custom_nodes/ and restart. No requirements.txt, no model downloads, just Pillow/numpy/torch that ComfyUI already ships.
Two gotchas worth remembering: the image picker only sees files in input/ (put your file there or upload through the node), and the earlier versions had a stuck-drag bug at high zoom that's fixed in 1.1.1 - if you're on an old install and panning feels broken, update. It's a fiddly node, but when you need to place an image by eye, it beats rebuilding that geometry with math nodes every single time.
Inputs (16)
| Name | Type | Default | Description |
|---|---|---|---|
| image | COMBO | 1 options: example.png | |
| canvas_width | INT | 5121–8192 | — |
| canvas_height | INT | 5121–8192 | — |
| padding_fill | COMBO | black | 6 options: black, white, gray_50, transparent, custom, noise |
| custom_color_hex | STRING | #000000 | — |
| noise_seed | INT | 00–18446744073709550000 | — |
| lock_aspect_ratio | BOOLEAN | true | — |
| locked_ratio | FLOAT | 1.00000.0001–10000 | — |
| zoom_x | FLOAT | 1.000.01–100 | — |
| zoom_y | FLOAT | 1.000.01–100 | — |
| offset_x | FLOAT | 0.500-1–2 | — |
| offset_y | FLOAT | 0.500-1–2 | — |
| flip_horizontal | BOOLEAN | false | — |
| flip_vertical | BOOLEAN | false | — |
| invert_mask | BOOLEAN | false | — |
| custom_color_hex_inputopt | STRING | — |
Outputs (3)
| Name | Type | Description |
|---|---|---|
| IMAGE | IMAGE | — |
| MASK | MASK | — |
| ORIGINAL IMAGE | IMAGE | — |