Nodes/ComfyUI-EditUtils/EditUtils: QwenImage 2.1 Config Preparer lrzjason
ComfyUI Node

EditUtils: QwenImage 2.1 Config Preparer lrzjason

One Ticket Per Reference Image

By lrzjason·Created 9 months ago·Updated 15 days ago· 246
EditUtils: QwenImage 2.1 Config Preparer lrzjason
  • image
  • configs
  • mask
  • configs
  • config
◄to_reftrue►
◄ref_main_imagetrue►
◄ref_longest_edge1024►
◄ref_croppad►
◄ref_upscalelanczos►
◄to_vltrue►
◄ref_resize_modelongest_edge►
◄rope_x_offset0►
◄rope_y_offset0►
◄pad_modecolor►
◄pad_colorwhite►
◄pad_color_rgb-►
◄pad_noise0.00►

A node that writes tickets instead of tensors

ComfyUI-EditUtils doesn't put its settings on the encode node. It builds a small list of dictionaries - one per image - and the encode node reads that list. QwenImage21ConfigPreparer_EditUtils writes exactly one entry into that list: this image, at this size, is a reference (or isn't), is the main image whose latent you sample from (or isn't), goes to the vision tower (or doesn't), and sits at this spot on the canvas.

On its own it computes nothing you can see. Chain three of them and you've described three references; chain eight and you've described eight - which is the real reason this node exists, since the pack's one-piece QwenImage21EditTextEncode_EditUtils stops at three images. The chain path has no cap.

Context, briefly: Qwen-Image-Edit is the model that made a whole adapter stack unnecessary - reference conditioning arrives as an image plus a plain-language instruction, no mask, no ControlNet, no IP-Adapter. 2.1 keeps that shape but changes the plumbing: prompt and references are encoded together by a Qwen3-VL text encoder, and each reference latent gets spliced into the text sequence at the encoder's vision slots. That's what the fields below are serving.

The mechanism the fields are serving

The encode node downstream does the work: it scales each image toward ref_longest_edge, snaps it to a multiple of 32 pixels, pads it to the VAE grid, encodes it, and hangs the resulting latents on the conditioning under reference_latents (plus the rope offsets under reference_rope_offsets). Qwen-Image 2.1's VAE is 64-channel with 16x spatial downscale, so 32 pixels is 16 × 2 - one vision slot maps onto a 2×2 group of latent tokens. Get that alignment wrong and the vision tower and the diffusion model are talking about different pixels.

That's why ref_longest_edge steps in 32s. Don't fight it.

The fields a beginner actually touches

  • image - the reference (or the main image; same input either way).
  • configs - the chain. Leave it empty on the first node, wire the previous node's configs output into it for every one after.
  • ref_main_image - the image whose padded latent becomes the sampling start latent. Exactly one node in the chain should have it on.
  • ref_longest_edge - 1024 to start. Bigger refs aren't automatically better; you're paying tokens for them.
  • to_vl - the author's tooltip says keep it enabled for trained behaviour, and the source agrees: with it off you're splicing a reference where the model was never trained to see one.

The rest are for when something is wrong: ref_crop (pad/center/disabled), ref_upscale (lanczos by default), ref_resize_mode (longest_edge matches ref_longest_edge to the long side; area matches total pixels to its square - a portrait and a landscape then cost the same), mask, and rope_x_offset / rope_y_offset, which only do anything if you also put QwenImage21EditApply_EditUtils in the graph.

Outputs

Two, and they're the same information: configs is the whole accumulated list - wire it to the next preparer or into the encode node's configs input. config is just this image's own dict, useful when you want to inspect it or hand a single entry to another node.

Install

ComfyUI Manager, search ComfyUI-EditUtils; or:

cd ComfyUI/custom_nodes
git clone https://github.com/lrzjason/ComfyUI-EditUtils

Restart ComfyUI. There's no requirements.txt here - the pack is plain Python over ComfyUI, so nothing extra gets pip-installed. The real dependency is your ComfyUI build: it needs upstream Qwen-Image 2.1 (qwen_image21) support. On an older build the model won't load at all. The example workflow loads qwen_image_2.1_int8_convrot.safetensors through UNETLoader, qwen3vl_8b_fp8_scaled.safetensors through CLIPLoader with type qwen_image, and qwen_image_2.1_vae_bf16.safetensors through VAELoader.

Where people get burned

to_vl=True together with to_ref=False looks like a sensible combo and isn't: the encoder forces to_ref back on and prints a note, because a vision slot with no latent behind it breaks the alignment. Set to_vl off if you want that image excluded from the references.

Two main images is a silent no-op - the second one's ref_main_image is forced to False, and if you set none at all the first image gets picked for you with a console note. Same shape of gotcha with mask: if its height and width don't match the image, it gets dropped and the run continues unmasked.

Finally, all-zero rope offsets are the native path, not a bug. If you wired the offsets expecting them to do something and nothing moved, check that the Edit Apply patch is actually in the graph.

Categoryadvanced/conditioning

Inputs (16)

NameTypeDefaultDescription
imageIMAGE—
configsoptLISTConfigs list
to_refoptBOOLEANtrueAdd image to reference latent
ref_main_imageoptBOOLEANtrueSet image as main image which would return the latent as output.
ref_longest_edgeoptINT102416–4096Reference target size. Snapped to 16-pixel multiples (16x VAE downscale).
ref_cropoptCOMBOpadCrop method for reference image
ref_upscaleoptCOMBOlanczosUpscale method for reference image
to_vloptBOOLEANtrueFeed the resized reference to the Qwen3-VL text encoder and splice its latent at the vision slot. Keep enabled for trained behavior.
maskoptMASK—
ref_resize_modeoptCOMBOlongest_edgelongest_edge: scale so the longest dimension equals ref_longest_edge. area: scale so total pixels equals ref_longest_edge squared.
rope_x_offsetoptINT00–4096ROPE horizontal position offset in pixels (16-aligned, matching the VAE downscale). Shifts reference rightward on the canvas. Requires QwenImage21EditApply_EditUtils.
rope_y_offsetoptINT00–4096ROPE vertical position offset in pixels (16-aligned, matching the VAE downscale). Shifts reference downward on the canvas. Requires QwenImage21EditApply_EditUtils.
pad_modeoptCOMBOcolorHow to fill the padding area when ref_crop == pad. color = solid pad_color, edge = replicate edge pixels, mirror = reflect content, border_mean = fill with the mean of the nearest edge pixels
pad_coloroptCOMBOwhitePad fill color when pad_mode == color: red / green / blue / white / black / custom. Default white for qwen image 2.1 since black pads get amplified during generation
pad_color_rgboptSTRING-Optional override: 6-digit hex color, with or without '#' (e.g. FF0000 or #FF0000). When valid it overrides pad_color. Anything else ("-", wrong length, non-hex, numbers, "r,g,b") is ignored
pad_noiseoptFLOAT0.000–0.2Gaussian jitter (std) added to the pad area to avoid perfectly flat regions; 0.02-0.05 recommended with solid colors

Outputs (2)

NameTypeDescription
configsLIST—
configANY—