EditUtils: QwenImage 2.1 Edit Apply (ROPE Control) lrzjason
Putting a Reference Where You Want It
- model
- model
One wire in, one wire out, no numbers on the face
QwenImage21EditApply_EditUtils has a model input, a model output, and a debug checkbox. That's the whole node. There is no "x offset" widget here, and that surprises people - the offsets live somewhere else, and this node is what makes them mean anything.
Here's the deal. Qwen-Image 2.1 natively splices reference latents into the text sequence at the encoder's vision slots and centres their RoPE positions on the target image. That's fine for "edit this picture" and useless for "put this person over there on the canvas." So EditUtils threads per-reference pixel offsets through the conditioning chain - you set rope_x_offset / rope_y_offset on QwenImage21ConfigPreparer_EditUtils - and this node installs the model patch that reads them. Drop it between UNETLoader and KSampler, connect only the model wire, and leave it alone.
Regional placement is the feature here, and it partly replaces the masking workaround: instead of Inpaint Crop → edit → Stitch, you tell the model where the reference sits. Handy, because the failure mode of whole-frame editing is that nothing pins the pixels you didn't ask about.
How the patch works
It's a real patch, not a passthrough. The node checks the model is Qwen-Image 2.1 (image_model == "qwen_image21", and the DiT has to expose build_sequence and pe_embedder), clones the model so the patch stays isolated to your graph, then installs three object patches:
extra_conds- pullsreference_rope_offsetsoff the conditioning and into the model's extra conds, which is how the values get from the preparer to the DiT at all.forward- stashes the per-reference offsets for the duration of the call.build_sequence- the payoff. Each reference's height/width position ids get the offset divided by 16 (the VAE's downscale, so offsets are authored in pixels and applied in latent units).
With every offset at zero the patched build_sequence just calls the original. That's deliberate: the native path stays byte-identical and the upstream prefix KV cache is unaffected. Zero offsets cost you nothing.
Inputs and outputs
model is required - your loaded Qwen-Image 2.1 UNET, before the sampler. debug_log is optional and prints the offsets that actually took effect, which is the first thing to turn on when nothing appears to move. The single output is model, wired onward to KSampler (or whatever else patches the model before it).
Getting offsets without doing arithmetic
The same pack ships RopeOffsetFromMask_EditUtils, which takes a black-and-white mask (or a B&W image) and returns rope_x_offset, rope_y_offset, region_width and region_height from the white region's bounding box, rounded to a VAE unit. Type those numbers into the preparer, use the region size for ref_longest_edge, and your placement follows the mask you drew instead of you eyeballing coordinates. Note the units: that node's vae_unit options are 8 and 16, so the offsets it hands you aren't snapped to the 32-pixel multiples the 2.1 preparer wants - check the padding behaviour on the main image if you care about exact pixel positions.
Install
ComfyUI Manager, search ComfyUI-EditUtils; or the usual:
cd ComfyUI/custom_nodes
git clone https://github.com/lrzjason/ComfyUI-EditUtils
Restart. No pip dependencies - but the node is inert without a ComfyUI build that has upstream Qwen-Image 2.1 support. The author says it plainly in the README: on older builds the model won't load, and this node passes the model through unchanged. Same file layout as the rest of the 2.1 path: qwen_image_2.1_int8_convrot.safetensors (UNETLoader), qwen3vl_8b_fp8_scaled.safetensors (CLIPLoader, type qwen_image), qwen_image_2.1_vae_bf16.safetensors (VAELoader).
When it doesn't do anything
The most common report is "I set offsets and the image didn't change," and the cause is usually that the detection failed - wrong model, or a ComfyUI too old to know the qwen_image21 route. The console tells you: the node prints QwenImage21EditApply_EditUtils: model is not QwenImage21, skipping patch and returns your model untouched. If you don't see that message and the offsets still do nothing, set debug_log to true; with it off, the node is silent about whether it applied an offset or took the native path.
Two more things worth internalising. Offsets are per reference and positional - the conditioning carries one entry per reference that went in via a config with to_ref on, so reordering your preparer chain reorders which offset lands on which image. And regional placement is a placement hint, not a mask: the model still re-emits the whole frame, so verify with your own eyes rather than assuming the rest of the picture is frozen.
Inputs (2)
| Name | Type | Default | Description |
|---|---|---|---|
| model | MODEL | — | |
| debug_logopt | BOOLEAN | false | — |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| model | MODEL | — |