〽️ Image Ops Corner Pin
Pin a screen onto anything — this is ComfyUI's Nuke-style CornerPin
- fill_color
- image
- image
- mask
If you've ever tried to paste a generated image onto a TV, a phone screen, or a billboard in a photo, you know the pain: free transform in some editor, eyeballing the perspective, doing it again after every render. ImageOps Corner Pin is the node that ends that. Drag the four corners of a quad directly on the preview, and it warps your image so it sits flat on whatever surface you pinned. It's the ComfyUI equivalent of the CornerPin2D node every compositor knows from Nuke, and it's one of the standout nodes in the ComfyUI-Majoor-ImageOps pack.
What it actually does
You feed it an image (or a batch of frames) and give it eight numbers - the destination X/Y of the top-left, top-right, bottom-left, and bottom-right corners, normalized so 0–1 spans the frame. Under the hood it solves a per-frame homography, runs the warp through PyTorch's grid_sample, and - the detail that separates this from a lazy paste job - premultiplies the alpha before warping and un-premultiplies after. That's why transparent edges stay clean instead of getting that dark fringed halo you see from naive warps. RGBA in means RGBA out, edges intact.
The real magic is the UI. You don't type the eight numbers. The node's live preview shows your image with four draggable corner handles - click and drag, no queueing, and the warp updates in real time. Handles snap to the frame edges (0 and 1) when you get close, which makes "exactly cover the screen" trivial; hold Alt while dragging to disable the snap and land anywhere, including slightly outside the frame.
The inputs that matter
tl_x / tl_y,tr_x / tr_y,bl_x / bl_y,br_x / br_y- the four destination corners in normalized coordinates. Defaults map the full frame (0,0 → 1,1). The allowed range goes to ±2 so you can push corners off-frame if the target surface is bigger than your source.supersample(1–4) - renders the warp at 2–4x and downsamples. This is your anti-aliasing knob for perspective edges; if diagonal lines come out jaggier than you'd like, bump it.fill_mode- what to do with the area outside your pinned quad.transparent(default) leaves it open so you can comp the result over anything;mirror,stretch,expand, andcolor(withfill_color) cover the edges instead.filter- nearest, bilinear (default), or bicubic resampling. Bilinear is fine; bicubic for the final pass.invert_maskflips the warped transparency mask, andbypassreturns the input untouched for quick A/B.
Wiring it up
Outputs are image and mask. The mask is the warped alpha - the transparent quad in image form - so you can feed it into a merge or comp node to place the result. A classic flow: load a photo of a room, pin your generated "screen content" onto the TV, then use ImageOps Merge (with the mask) to composite it in. Because it's batch-first, a video clip pins onto a moving TV as a per-frame homography - genuinely useful for animation work.
Install and gotchas
Install via ComfyUI Manager (search "ComfyUI-Majoor-ImageOps") or:
cd ComfyUI/custom_nodes
git clone https://github.com/MajoorWaldi/ComfyUI-Majoor-ImageOps
Then restart ComfyUI and hard-refresh your browser (Ctrl+F5 / Cmd+Shift+R). No model downloads, no extra Python deps - it's pure torch. If the corner handles don't appear on the preview, the refresh is almost certainly the fix; the preview UI is frontend JavaScript and stale cache is the classic culprit.
One tip from real use: pin with the destination quad slightly larger than the surface and let fill_mode handle the overlap - a hair of overhang hides misalignment. And if your pinned content looks soft, it's the supersample, not your perspective. Crank it for the final render.
Inputs (15)
| Name | Type | Default | Description |
|---|---|---|---|
| bypass | BOOLEAN | false | — |
| tl_x | FLOAT | 0.000-2–2 | — |
| tl_y | FLOAT | 0.000-2–2 | — |
| tr_x | FLOAT | 1.000-2–2 | — |
| tr_y | FLOAT | 0.000-2–2 | — |
| bl_x | FLOAT | 0.000-2–2 | — |
| bl_y | FLOAT | 1.000-2–2 | — |
| br_x | FLOAT | 1.000-2–2 | — |
| br_y | FLOAT | 1.000-2–2 | — |
| filter | COMBO | bilinear | 3 options: nearest, bilinear, bicubic |
| supersample | INT | 1 | Render at 2x-4x and downsample to reduce perspective aliasing. |
| fill_mode | COMBO | transparent | How to fill uncovered areas outside the pinned quad. |
| fill_color | COLOR | #000000 | — |
| invert_mask | BOOLEAN | false | — |
| imageopt | IMAGE,VIDEO | Images/Video input. Accepts IMAGE batches and VIDEO frame sources. |
Outputs (2)
| Name | Type | Description |
|---|---|---|
| image | IMAGE | — |
| mask | MASK | — |