ImageScaleRestore_YC
Scale an image and its mask as one unit — then hand the original size back so you can restore it
- image
- mask
- original_size
- image
- mask
- original_size
- width
- height
Most resize nodes give you a resized image and leave you to figure out the mask separately. ImageScaleRestore_YC is built for the crop-edit-stitch inpainting pattern instead: it scales an image and its mask together so they stay aligned, and it hands you the original dimensions as a BOX output - the thing you need to put the result back where it came from.
The intended loop is: crop around your target region, upscale it so the edit model has real pixels to work with, do the edit, then restore to the original size and stitch back. That's the 2026 community standard for inpainting - never run the whole frame through the VAE, only process the region you care about (see the "crop, edit, stitch" section of the inpainting essay). This node is the "scale" and "unscale" step of that loop in one place.
How it works
It's a plain PIL resize under the hood, with a method picker (lanczos, bicubic, hamming, bilinear, box, nearest) and a scale_by selector that decides what your target actually means:
by_scale- thescalemultiplier, so 2.0 doubles the image.longest/shortest- fit the longest (or shortest) edge toscale_by_length.width/height- pin one edge toscale_by_length, scale the other proportionally.total_pixel(kilo pixel)- target a total megapixel-ish budget.
The mask rides along, resized with the same sampler. If you don't feed a mask, you get back a solid white one at the new size, which is a deliberate default - a white mask means "select everything," so the node never breaks a downstream graph just because you forgot to wire one in.
The two inputs that matter most beyond the obvious: mask, which you almost always want when you're scaling a crop for editing, and original_size (BOX). When you pass one in - and the natural source is the original_size output from an earlier run of this same node - it ignores the scale math entirely and just resizes to that exact size. That's the "restore" half: scale up, edit, then scale back to the stored dimensions.
Outputs
Five of them: image, mask, original_size (a BOX of the input's dimensions), and width / height as plain integers you can route into anything that needs the target resolution. If you're chaining this into MaskCropRestore_YC or an ImageCompositeMasked stitch step, original_size is the piece you actually want.
Install
This ships in the ComfyUI-YCNodes pack. ComfyUI Manager → Install Custom Nodes → search "ComfyUI-YCNodes", or:
cd ComfyUI/custom_nodes
git clone https://github.com/yichengup/ComfyUI-YCNodes
Restart ComfyUI. Dependencies are torch, numpy, pillow, opencv-python and scipy - nothing exotic, no model downloads. One quirk of this pack: the README barely documents the mask and scale nodes (it's mostly about the Image IC combo nodes), so the code is the actual doc. And the README's own clone command uses a placeholder URL - use the real repo above.
Gotchas
Two, both from reading the code. If original_size is supplied, scale, scale_by and scale_by_length are all ignored - the node becomes a pure "resize to this box" pass, so don't fight it by setting both. And there's a hard 4-pixel floor on either dimension, which is honestly a safety feature more than a limit. Everything else is predictable: give it a batch and it processes frame by frame, so your masks and images stay in lockstep.
Inputs (7)
| Name | Type | Default | Description |
|---|---|---|---|
| image | IMAGE | — | |
| scale | FLOAT | 1.000.01–100 | — |
| method | COMBO | 6 options: lanczos, bicubic, hamming, bilinear, box, nearest | |
| scale_by | COMBO | 6 options: by_scale, longest, shortest, width, height, total_pixel(kilo pixel) | |
| scale_by_length | INT | 10244–99999999 | — |
| maskopt | MASK | — | |
| original_sizeopt | BOX | — |
Outputs (5)
| Name | Type | Description |
|---|---|---|
| image | IMAGE | — |
| mask | MASK | — |
| original_size | BOX | — |
| width | INT | — |
| height | INT | — |