Nodes/AM VFX Tools/AM Read Image
ComfyUI Node

AM Read Image

LoadImage, rebuilt for EXR sequences and real color

By am-pipeline-prod·Created 4 months ago·Updated 3 months ago· 3
AM Read Image
    • image
    • mask
    • resolved_path
    • info
    • width
    • height
    • frame_rate
    • frame_count
    • video
    file_path
    frame_modeall
    frame_rate-1.00
    first_frame1
    last_frame1
    missing_framesblack
    beforehold
    afterhold
    input_colorspaceACES/ACES2065-1
    raw_datafalse
    working_colorspaceDisplay/sRGB - Display
    reformat_modeoff
    scale1.00
    presetWidth/Height
    target_width1920
    target_height1080
    resize_typefit
    filtercubic
    output_dtypefp16
    show_previewtrue

    Stock LoadImage reads PNGs from ComfyUI/input/ and calls it a day. AM Read Image is the node you reach for the moment your source material stops being PNGs in a folder and starts being EXR/DPX/TIFF sequences on a render drive. OpenImageIO-backed, it reads basically any image format a studio produces, understands frame sequences, color-manages them into your working space, and splits alpha out the way ComfyUI expects.

    It's part of comfyui-am-vfx-tools ("AM VFX Tools" category), Adrian Meyer's 13-node VFX toolkit - the public slice of an internal studio pipeline. The OIIO read path started from sumitchatterjee13/nuke-nodes-comfyui and was rewritten substantially, which is why it smells like a real I/O node rather than a toy.

    How it works

    The core idea is a frame-token path: instead of loading one file, you give it a pattern and it expands it. All three VFX conventions work:

    /work/shots/sh010/plate.0001.exr        # single frame
    /work/shots/sh010/plate.####.exr        # 4-digit zero-pad
    /work/shots/sh010/plate.%05d.exr        # printf style
    /work/shots/sh010/plate.$F4.exr         # Nuke style
    

    Then a frame_mode decides what to load: single (just first_frame), range (a window, with before/after edge policies of hold/loop/bounce/black), or all (every frame on disk). There's a missing_frames policy for gaps - error, black, checkerboard, hold, or nearest - which is the difference between a render failing and a render limping through a dropped frame. The 🔍 Detect Range button next to the frame fields scans the directory and auto-fills the window.

    The inputs that matter

    • file_path - the path or sequence pattern. Use the 📂 Browse button; it opens the OS-native file dialog.
    • input_colorspace / working_colorspace - the OCIO transform from the file's tagged (or assumed) space into the space downstream nodes see. raw_data skips the transform entirely if you want pixels verbatim.
    • frame_mode + first_frame/last_frame - what to load.

    Everything else - reformat-to-box, scale, filter, and an output_dtype (fp16 default, half the RAM; flip to fp32 if a downstream node complains) - is convenience baked into the read.

    Outputs

    image (RGB, N×H×W×3), mask (alpha, following the stock convention where mask = 1 - alpha, so white = transparent/inpaint area - wire a MaskInvert if you want Nuke-style natural alpha), resolved_path, info, width, height, frame_rate, frame_count, and a video socket. That last one is a VideoFromComponents convenience wrapper around the already-decoded batch - no RAM benefit, it's just there so you can feed stock video nodes. The real RAM trick is on AM Read Video's video socket, which is a true file reference.

    Installing it

    cd ComfyUI/custom_nodes
    git clone https://github.com/am-pipeline-prod/comfyui-am-vfx-tools.git
    cd comfyui-am-vfx-tools
    pip install -r requirements.txt
    

    Restart ComfyUI, or search comfyui-am-vfx-tools in ComfyUI Manager. The openimageio dependency (imports as OpenImageIO) comes from that pip line.

    Where people get burned

    The frame token. Forget the #### and type a literal plate.0001.exr, and you load one frame and wonder why the sequence "isn't a sequence." Also: missing frames default to black, which silently inserts black frames into your batch - flip it to error if you'd rather a render fail loudly than ship a black hole. And if your existing ComfyUI environment wasn't built with EXR support, set export OPENCV_IO_ENABLE_OPENEXR=1 before launch - the pack sets it in-process, but an earlier custom node that touched OpenCV may have already committed to the default.

    CategoryAM VFX Tools

    Inputs (20)

    NameTypeDefaultDescription
    file_pathSTRINGAbsolute path to the file or image sequence. For sequences, use a frame token: ``####`` / ``%05d`` / ``$F4`` style. Use the 📂 Browse button to populate from the native file dialog.
    frame_modeCOMBOallWhich frames to load. single = only `first_frame`. range = `first_frame`..`last_frame` inclusive (with `before`/`after` policy at edges). all = every present frame in the resolved directory.
    frame_rateFLOAT-1.00-1–480Frame rate for the `frame_rate` output socket. -1 = auto: probe EXR/OIIO metadata (framesPerSecond, input/framesPerSecond, frameRate, framerate, fps); fallback 25 fps. Any other value = explicit override.
    first_frameINT1-999999–999999Frame index in single mode; lower bound in range mode. Ignored in all mode. The 🔍 Detect Range button auto-fills this.
    last_frameINT1-999999–999999Range upper bound (inclusive). Used in range mode only. The 🔍 Detect Range button auto-fills this from the on-disk scan.
    missing_framesCOMBOblackPolicy when a frame inside the requested set is missing on disk. error = abort the load. black / checkerboard = synthesize a placeholder. hold = repeat the last successful frame. nearest = use the nearest existing frame number.
    beforeCOMBOholdEdge policy below the on-disk range when `frame_mode=range`. hold = clamp to first frame; loop = wrap; bounce = ping-pong; black = synthesize black.
    afterCOMBOholdEdge policy above the on-disk range when `frame_mode=range`. Mirrors `before` — same options, applied at the upper edge.
    input_colorspaceCOMBOACES/ACES2065-1Source colorspace of the file. The OCIO transform converts from this to `working_colorspace`. Pick `raw` to honor the file's own tagged colorspace; pick a specific value to override.
    raw_dataBOOLEANfalseWhen On, skip the OCIO transform — pixels pass through unchanged. `input_colorspace` and `working_colorspace` are ignored.
    working_colorspaceCOMBODisplay/sRGB - DisplayTarget colorspace for the IMAGE output — the space downstream nodes (Grade, samplers, ...) will see.
    reformat_modeCOMBOoffReformat mode. off = bypass, output matches input. scale = uniform scale by `scale` (other widgets ignored). to_box = resize/crop to a target W×H from `preset` or `target_width`/`target_height`.
    scaleFLOAT1.000.01–16Uniform scale factor. Used when `reformat_mode=scale`; ignored otherwise. Output dimensions are round(input × scale).
    presetCOMBOWidth/HeightNamed output format. Used when `reformat_mode=to_box`. `Width/Height` = use the `target_width` / `target_height` widgets below. Any other entry overrides those widgets with the preset's resolution.
    target_widthINT19201–16384Target output width in pixels. Used when `reformat_mode=to_box` AND `preset=Width/Height`; ignored when a named preset is selected.
    target_heightINT10801–16384Target output height in pixels. Used when `reformat_mode=to_box` AND `preset=Width/Height`; ignored when a named preset is selected.
    resize_typeCOMBOfitHow input maps into the target box. Used when `reformat_mode=to_box`. width/height = scale uniformly to match that edge. fit = scale to fit inside the box (letterbox; black where the box exceeds the scaled image). fill = scale to cover the box (crops the overflow). distort = scale W and H independently to exactly match the box (changes aspect). none = no scale; place input centered in the box (crop if larger, pad if smaller). Cropped-away/padded regions are TRANSPARENT — RGB sources are promoted to RGBA with alpha=0 in the padded area so downstream compositing is clean.
    filterCOMBOcubicPixel filter for resampling. impulse = nearest-neighbor (mask passes, exact pixel preservation). linear = bilinear (cheap, smooth). cubic = bicubic (default; the safe Nuke-equivalent). Lanczos4 = sharpest; for high-quality stills / final delivery. area = best for downscaling — anti-aliased mean pooling, softer but artifact-free.
    output_dtypeCOMBOfp16Output tensor dtype. fp32 = ComfyUI default (4 bytes/sample). fp16 = half memory + half VRAM (2 bytes/sample). EXR-native precision; fits the [0,1] LDR + scene-linear range with headroom up to ~65504. Some downstream nodes assume fp32 — flip back to fp32 if you hit dtype errors.
    show_previewBOOLEANtrueShow a thumbnail of the loaded frame on the node.

    Outputs (9)

    NameTypeDescription
    imageIMAGEFrame batch as IMAGE (N×H×W×3 float in [0,1]). RGB only — alpha is split out to the `mask` socket per stock-ComfyUI convention.
    maskMASKAlpha channel as MASK (N×H×W float in [0,1]). MASK CONVENTION (stock ComfyUI): mask = 1 - alpha white (1.0) = 'area to inpaint' (source was transparent) black (0.0) = 'keep' (source was opaque) empty mask = all zeros (source has no alpha = fully visible) This is the SD-inpainting convention every stock ComfyUI mask-using node expects (LoadImage, MaskComposite, SetLatentNoiseMask, ImpactPack mask pipeline, etc.). Drop-in compatible with all of them. If you want NUKE-STYLE natural alpha (mask = alpha, where 1.0 = opaque), wire a MaskInvert node between this socket and your downstream consumer. Populated when the source carries alpha: * Image: EXR / PNG / TIFF with α channel * Video: ProRes 4444 / 4444 XQ, QuickTime RLE, FFV1 (yuva*) Otherwise emits the empty mask (zeros = fully opaque source).
    resolved_pathSTRINGResolved on-disk path of the last successfully read frame.
    infoSTRINGHuman-readable summary: dimensions, bit depth, source colorspace, frame count.
    widthINTFrame width in pixels.
    heightINTFrame height in pixels.
    frame_rateFLOATEffective fps. From the `frame_rate` widget when set, else probed from EXR/OIIO metadata, else 25 fallback.
    frame_countINTNumber of frames in the IMAGE batch.
    videoVIDEOConvenience VIDEO wrapper (`VideoFromComponents`) around the same IMAGE batch + frame_rate. NO RAM benefit — frames are already decoded. Equivalent to wiring `Create Video` downstream. Native `SaveVideo` only accepts this as MP4+H264; use AM Write Video for other codecs.