CropByMaskRestore
Put the refined crop back where it came from, seam and all
- cropped_image
- cropped_mask
- crop_data
- original_image
- restored_image
CropByMaskRestore is the "paste back" half of the classic detect-crop-refine loop, and it deserves more attention than it gets. The whole point of cropping a region out of an image is to process that region at proper resolution - detail it, inpaint it, fix it - and then get it back into the original without a visible seam. This node is that return trip. Give it the processed cropped_image, the original original_image, and the crop_data the crop step produced, and it stitches the fixed region back into place.
It's a direct cousin of Impact Pack's "detect, crop, resample at full resolution, paste back" core mechanism that the KB's masking-detection-detailing doc documents - the loop behind FaceDetailer and every regional refiner. CropByMaskRestore implements the final step: rather than throwing a processed region back as a hard rectangle, it uses the cropped_mask to blend. The mask's alpha is inverted into a soft edge, the processed crop is resized to the crop coordinates, and blend_hardness (0–1, default 0.5) controls how feathered that edge is. Below 0.95 it even applies a light Gaussian blur along the transition band (wherever the mask alpha sits between 5% and 95%), which is the difference between a pasted patch and a region that looks like it was always there.
The crop_data input is the key piece and it's the thing beginners fumble. It's a CROP_DATA container that encodes everything the crop step knew: crop coordinates, destination offset, mask dimensions, the scale factors, and the canvas size. The node reads all twelve values per batch item and uses them to position the processed crop exactly where the original sat - including the full-canvas fast path where the crop covered the whole image, in which case it just resizes back and skips the compositing entirely. That's why the restore step can't be faked with a generic paste node: without the crop metadata it doesn't know where "back" is.
Practically, this node expects a specific pipeline: something crops by mask (the pack's own CropByMask is the natural partner, and it emits the matching CROP_DATA), your refinement runs on the crop, and this node reassembles. It's built to work on batches - it processes as many items as the smaller of the original batch and the crop data length, and if any single item fails to restore it quietly passes the original image through rather than killing the run. That's the right call for unattended batch work.
Installing it
cd ComfyUI/custom_nodes
git clone https://github.com/Ginolazy/ComfyPanel
# restart ComfyUI
Or ComfyUI Manager → "ComfyPanel". Standard deps (torch, opencv-python, numpy, Pillow, kornia, scipy); no models. The CROP_DATA type comes from this pack, so you can't feed it metadata from a different pack's crop node - keep the crop and restore halves of the pipeline inside ComfyPanel unless you know the types match.
Where it fits in your workflow: any time you process a masked region and want the result composited back cleanly - fixing a face, re-texturing a region, running a local inpaint. If your crop-and-fix currently ends with a hard-edged box in the output, this node is the missing seam-blender you've been avoiding writing by hand.
Inputs (5)
| Name | Type | Default | Description |
|---|---|---|---|
| cropped_image | IMAGE | — | |
| cropped_mask | MASK | — | |
| crop_data | CROP_DATA | — | |
| original_image | IMAGE | — | |
| blend_hardness | FLOAT | 0.500–1 | — |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| restored_image | IMAGE | — |