Nodes/X-WIDE Image / Latent Sender / Receiver/X-WIDE Latent Receiver 潜空间接收器
ComfyUI Node

X-WIDE Latent Receiver 潜空间接收器

The latent that came out of a PNG's EXIF

By XWIDE·Created 22 days ago·Updated 22 days ago· 2
X-WIDE Latent Receiver 潜空间接收器
    • latent
    ◄latent▾►
    ◄link_id0►
    ◄trigger_alwaysfalse►

    The node is trivial - one dropdown, one output, one number - but the file it reads is odd: a latent that arrived as a picture, stuffed into a PNG's metadata block. That explains everything about how it behaves, including why it sometimes hands you an empty latent with a shrug.

    What it is

    XWIDE_LatentReceiver is the receiving half of the X-WIDE latent pair, a standalone re-wrap of ltdrdata's Impact Pack Latent Receiver (GPL-3.0, no Impact Pack needed, protocol-compatible with the original). You reach for it when a graph needs a latent produced somewhere else - a feedback loop, a pipeline split across the canvas, or a second workflow tab on the same machine.

    The payoff over the image pair is skipping a VAE decode and encode. Both are lossy, and workflows that repeatedly round-trip through the VAE accumulate that damage - passing the tensor keeps the second half of the pipeline working on exactly what the first half produced.

    How it works

    The sender writes temp/latents/<name>_00001_.latent.png: a Latent2RGB preview with the safetensors-serialized latent zipped into the PNG's EXIF UserComment, and fires a latent-send event. Every receiver whose link_id matches gets that filename written into its latent dropdown as an annotated path - latents/LatentSender_00001_.latent.png [temp] - plus a preview on the node. The bracket is the important part: [temp] tells the backend to look in the scratch folder rather than input/.

    On execution it reads that path and reconstructs the tensor. For a .latent.png it opens the image, pulls the EXIF block with piexif, reads the zipped latent entry, and safetensors loads it back into a proper {"samples": ...} dict. For a plain .latent it loads the safetensors file directly - and if that file lacks the latent_format_version_0 marker (an old-style file holding an unscaled latent) it applies the same 1/0.18215 multiplier ComfyUI's LoadLatent uses, so you never get a doubled or halved latent. This pack's own files always carry the marker, so nothing gets scaled twice.

    IS_CHANGED here is better than the image receiver's: it SHA-256s the file's bytes rather than hashing the filename, so a genuinely different latent re-triggers execution. trigger_always overrides it with the classic always-dirty NaN return.

    Inputs and outputs

    • latent - the file picker, auto-filled by the sender. It also lists .latent and .latent.png files from ComfyUI/input/, so you can point it at one you stashed there yourself.
    • link_id - pairing number, default 0, must match the sender.
    • trigger_always - false by default; force a re-run each queue.

    The single output is latent (LATENT). Wire it into KSampler's latent_image, a VAEDecode, a latent upscaler, whatever comes next - anything taking a normal LATENT will accept it, because that's what it is. No custom type for downstream nodes to learn.

    Install

    cd ComfyUI/custom_nodes
    git clone https://github.com/XWIDE/comfyui-x-wide-image-latent-sender-receiver
    

    Restart, then Ctrl + F5 - the latent-send listener is front-end JavaScript, so a cached page means the node never updates. Manager users can search X-WIDE Image Latent Sender / Receiver. Zero downloads, zero pip install: the dependency list is empty, and it leans on libraries ComfyUI already ships (piexif, safetensors, torch/numpy/Pillow). The GitHub repo was renamed in October 2026; the shorter legacy URL redirects, so both clone commands work.

    Where people get burned

    You get a tiny blurry result. That's the fallback, not a model problem: when the file can't be found or read, the node logs a warning and outputs an empty latent, shape 1×4×8×8, which decodes to a 64×64 image. Since temp/ is cleared on restart, an old workflow reopened the next day is exactly this case. Re-run the sender once.

    It used to red-box instead of degrading. In the original, a missing latent file was rejected at validation, so a wall of reopened workflows turned red after a restart. This version only rejects absolute paths and .. traversal, downgrading a missing file to a warning - and fixes a subtle bug where an unconnected receiver returned a bare tensor instead of a {"samples": ...} dict, breaking downstream nodes with a confusing type error.

    Reaching for it when you don't need it. If both halves of your graph are already joined by a visible wire, skip this pair. It's for crossing a gap the graph can't express - reuse across runs, or a handoff between tabs - and it hands off between runs: the receiver reads the filename it held at queue time, so a send lands on the next execution.

    Sharing the latent with someone. Hand over the .latent.png; they can load it with this node or the original. Don't convert or screenshot it - the tensor lives in the EXIF block, and re-encoding throws it away like any other metadata.

    CategoryX-WIDE/Latent

    Inputs (3)

    NameTypeDefaultDescription
    latentCOMBO要读取的 latent 文件(.latent 或带预览的 .latent.png)。收到 Sender 发来的文件后这里会自动填入。 / Latent file to load (.latent, or a preview .latent.png). Filled automatically with the received file.
    link_idINT00–9223372036854776000配对编号:和 Latent Sender 的 link_id 相同才会收到它的 latent。 / Pairing id: only the Sender with the same link_id will send to this node.
    trigger_alwaysBOOLEANfalse开启后本节点每次都重新执行(忽略缓存)。 / When enabled the node always re-executes, ignoring the cache.

    Outputs (1)

    NameTypeDescription
    latentLATENT—