Nodes/🌐 Universal Media Loader/Universal Image Unpack
ComfyUI Node

Universal Image Unpack

The node that turns a dropped file into image, mask, and RGBA β€” in one shot

By FictiverseΒ·Created 21 days agoΒ·Updated 19 days agoΒ· 13
Universal Image Unpack
  • media_data
  • image
  • mask
  • rgba_image
  • width
  • height
  • orig_width
  • orig_height
  • megapixels
  • crop_x
  • crop_y
  • crop_w
  • crop_h
  • filename

You drop an image on UniversalMediaLoader, and this is the node that actually does something with it. UniversalImageUnpack reads the loader's MEDIA_DATA, decodes the file, applies everything you did visually - the crop box, the mask you painted, flips and rotation - and hands you a ready-to-use IMAGE tensor, a MASK, and an RGBA version, all in one go. It's the answer to the workflow where you'd otherwise chain a loader, a crop node, a mask node, and a resize node together and still fight about pixel alignment.

How it works

The node takes one optional input, media_data, and does three jobs server-side:

  1. Locate and decode. It reads the filename from the JSON, finds it in ComfyUI's input/ folder, and opens it with Pillow (auto-correcting EXIF orientation).
  2. Apply your edits. Crop coordinates from the loader's visual crop box are applied - including outpaint mode, where the crop extends past the image edge: missing areas get filled black and the mask fills white, so an outpaint workflow gets its mask for free. Megapixel clamping and 32px grid snapping run here too.
  3. Composite the mask. Whatever you painted with the inpaint brush comes through as the mask output. The rgba_image output carries that mask inverted as its alpha channel - the painted region is transparent, the rest opaque - which is exactly the convention ComfyUI's inpaint nodes expect.

The surprise feature: video and GIF input

Connect this node to a loader that has a video or GIF dropped on it and you don't get a full frame dump. You get a batch of exactly three keyframes: [Trim Start, Current Playhead Position, Trim End]. That's the pack's answer to "show me the start, the bit I care about, and the end" for a video-to-image inpaint or style pass. Want every frame instead? That's what UniversalVideoUnpack is for - this node is deliberately sampling, not decoding.

Wire the wrong media in and you still get something safe: an audio file yields a minimal black 32Γ—32 placeholder with zeroed metadata rather than a crash.

The outputs that matter

  • image - RGB tensor, normalized 0.0–1.0. Straight into your VAE, sampler, or ControlNet preprocessor.
  • mask - your painted inpaint region (white = edit here). Feed it to Set Latent Noise Mask or any inpaint path.
  • rgba_image - 4-channel version with the mask as alpha, handy for compositing.
  • width / height - the output dimensions after crop/snap; orig_width / orig_height are the source's. crop_x / crop_y / crop_w / crop_h give you the bounding box so downstream nodes know what happened.
  • filename - the source file name, handy for filenames and logging.

Installing

Same pack as the loader: ComfyUI Manager, search "Universal Media Loader", or:

cd ComfyUI/custom_nodes/
git clone https://github.com/Fictiverse/ComfyUI_UniversalMediaLoader.git

Restart ComfyUI. No extra Python packages, no model downloads.

Where people trip

The three-keyframe behavior is the one that surprises everyone - you drag a video in expecting frames and get a batch of 3. It's a feature, but if you were chasing "decode all frames," you're in the wrong unpack. Also remember: the mask is only as good as what you painted in the loader. Nothing painted, all black, and an inpaint will happily regenerate the whole frame - check your brush strokes before you queue.

Categoryloaders/universal_media

Inputs (1)

NameTypeDefaultDescription
media_dataoptMEDIA_DATAβ€”

Outputs (13)

NameTypeDescription
imageIMAGEβ€”
maskMASKβ€”
rgba_imageIMAGEβ€”
widthINTβ€”
heightINTβ€”
orig_widthINTβ€”
orig_heightINTβ€”
megapixelsFLOATβ€”
crop_xINTβ€”
crop_yINTβ€”
crop_wINTβ€”
crop_hINTβ€”
filenameSTRINGβ€”