Nodes/PortraitUtils/Paired Image Loader
ComfyUI Node

Paired Image Loader

Before-and-after, one pair per queue

By heyburns·Created about a year ago·Updated 23 days ago· 3
Paired Image Loader
    • output_image
    • source_image
    • filename
    ◄source_dir►
    ◄output_dir►
    ◄reversefalse►
    ◄strip_trailing_numbersfalse►
    ◄color_managementConvert to sRGB►
    ◄alpha_backgroundWhite►

    What it's for

    Nobody wants to compare retouches one file dialog at a time. If you've got a folder of originals and a folder of the same names after whatever pipeline you're evaluating - your own edits, a new model, an upscaler - this node walks both folders in lockstep and hands you the pair.

    That's the whole use case: before/after. It feeds a comparison viewer, an image-compare node, a side-by-side compositor, or a GIF/video out of the same stack. It is not a general-purpose loader, and it isn't trying to be.

    How it works

    Four required inputs: source_dir and output_dir (the two folders), reverse (walk backward instead of forward), and strip_trailing_numbers. Two optional: color_management (Convert to sRGB by default, or Keep encoded values) and alpha_background (White or Black).

    Matching is by basename, case-insensitively, and the extensions are allowed to differ - so IMG_0042.jpeg in the originals pairs with IMG_0042.png in the output folder if that's how your tooling named things. Sorting is natural, so image2 comes before image10 rather than the usual lexicographic mess. With strip_trailing_numbers on, a trailing copy marker like photo (2) is ignored for matching - which is exactly what you want when a retoucher's export pipeline appends a browser-style duplicate suffix.

    Outputs, in order: output_image, source_image, and filename - the source stem without its extension, which is what you'd feed to a text overlay or a saver if you want the before/after files named consistently.

    One pair per queued execution, then it wraps around. reverse steps backward through the list instead. Directories can be absolute or relative to the process working directory, which is worth noting because other loaders in this pack resolve relative paths against ComfyUI/input - different rule, different node.

    The cursor is transactional: it only commits after both files decode. A pair that fails gets retried on the next run rather than being skipped forever, which is the right behaviour when you're mid-export and one file is still being written.

    Where people get burned

    Caching. Advancing through a folder requires ComfyUI's normal caching mode. If you're running in a no-cache mode, node objects aren't retained and the sequencing isn't there. If pressing Queue keeps handing you pair one, that's your answer before you go looking at the folders.

    Features this node doesn't have. Worth stating because older docs for the 1.x version claimed them: there's no pattern template, no shuffle, no index socket, no singleton output, and no auto-next or loop switch. You get directory pairs, ordering, reverse, and a cursor. If you need something more elaborate, that's a different node.

    File naming mismatches. The matching is basename-only, so a retoucher who renamed exports (photo_final_v3.png) will simply not be found. And the folders are walked as sets - a file present on one side with no counterpart on the other just reduces how much you can walk, silently.

    Also worth remembering: this is a still-photo loader. Animated or multipage files load their first frame only, and 32-bit/HDR sources fail with guidance rather than being silently clipped.

    The metadata angle

    Keep your originals. The whole reason to run a paired comparison is to see whether a pipeline degraded something, and comparing JPEGs to JPEGs after two rounds of re-encoding tells you very little. PNG on both sides, and remember that a ComfyUI PNG carries its workflow graph in the file - so the "before" folder of a ComfyUI-produced set is also a folder of loadable workflows.

    Install

    ComfyUI Manager → search PortraitUtils (publisher heyburns, GPLv3), or:

    cd ComfyUI/custom_nodes
    git clone https://github.com/heyburns/PortraitUtils
    /path/to/ComfyUI/venv/bin/python -m pip install -r PortraitUtils/requirements.txt
    

    The pack installs numpy, Pillow>=9.1, opencv-python-headless>=4.10.0.84 and tifffile into ComfyUI's Python environment - one OpenCV variant only. Decoding here uses the same colour- and precision-aware engine as PortraitUtils' other loaders, so 16-bit PNG and TIFF sources keep their samples. Restart the ComfyUI server after installing; a browser refresh won't reload nodes.

    CategoryPortraitUtils/IO

    Inputs (6)

    NameTypeDefaultDescription
    source_dirSTRING—
    output_dirSTRING—
    reverseBOOLEANfalse—
    strip_trailing_numbersBOOLEANfalseStrip trailing " (n)" suffixes before matching.
    color_managementoptCOMBOConvert to sRGB2 options: Convert to sRGB, Keep encoded values
    alpha_backgroundoptCOMBOWhite2 options: White, Black

    Outputs (3)

    NameTypeDescription
    output_imageIMAGE—
    source_imageIMAGE—
    filenameSTRING—