Image Catalog Indexed
Your reference images, stored once and picked by number
- IMAGE
- property_1
- property_2
- property_3
- property_4
- property_5
- property_6
- property_7
- property_8
- property_9
- property_10
- property_11
- property_12
- property_13
- property_14
- property_15
- property_16
- property_17
- property_18
- property_19
- property_20
- property_21
- property_22
- property_23
- property_24
- property_25
- property_26
- property_27
- property_28
- property_29
- property_30
- property_31
- property_32
Every img2img session starts the same dumb way: drop a file into Load Image, run, swap the file, run again. Ten reference images mean ten rounds of file-picking, and which image went with which prompt lives in your head or in a filename.
Image Catalog Indexed turns that into a number. Curate a persistent catalog once, with typed properties attached, and the node hands the graph one image per run, chosen by image_index. It's the dataset-sidecar convention - image plus metadata - with a UI and an index instead of a folder of .txt files and a file picker.
What you actually get
It's a graph output node, so it runs even with nothing wired downstream: a pick-and-preview selector, not just a feeder. The selected record emits its image plus every property value in the schema.
That makes it the node for testing one prompt against a fixed reference set, walking a character sheet one pose per run, or driving a graph from per-image fields (caption, subject, seed) you'd otherwise retype. If you actually want "loop over every file in a folder in one batch," a folder batch loader - Inspire's Load Image Batch from Dir, WAS's batch loader - is the tool, not this.
The inputs and outputs that matter
Two inputs, and you only touch one.
image_index(INT, default 0) - zero-based into the list of visible records, and out-of-range values wrap around (index % visible_count): index 7 in a 4-image catalog quietly gives you the fourth image rather than an error. It's the only connectable input; wire a primitive in and automatic index control defers to your value.catalog_state(STRING, default"{}") - leave it alone. The frontend fills it with the catalog id plus the node's local snapshot; API clients pass a serialized one to run headlessly.
Outputs run IMAGE first, then up to 32 property slots in schema order. The image arrives as a [1, height, width, 3] RGB tensor of 0–1 floats, ready for a VAE Encode, an edit-model reference, or a ControlNet preprocessor. Stored PNGs keep their alpha, the output doesn't: it's decoded to RGB, so don't catalog transparent cutouts expecting a mask out the other end. Animated files give you the first frame.
The property outputs are dynamically typed (*), with a deliberate source hack - a string subclass whose __ne__ always returns False - so older frontends don't reject them. ComfyUI won't type-check those wires either, so plugging an INT property into a STRING input looks fine until it runs.
Under image_index sits another dropdown, Index after queue, added by the pack's frontend extension rather than declared in the input schema. It's control_after_generate for this node - fixed, increment, decrement, randomize - and it inherits the same trap: it fires after a prompt is queued, so it shows the index that will run next. To re-run the image you just got, switch to fixed first.
Installing it
No model downloads, nothing to pip install: the runtime uses the PyTorch, NumPy, Pillow and aiohttp ComfyUI already ships (the pack declares zero runtime dependencies). Python 3.10 or newer.
cd ComfyUI/custom_nodes
git clone https://github.com/ArtemKo7v/ComfyUI-ImageCatalogIndexed
# restart ComfyUI, then hard-refresh the browser tab
Or search Image Catalog Indexed in ComfyUI Manager - it's registry-published. The browser refresh matters, since the editing UI is a JS extension. Files land outside the normal image folders, so Load Image never sees them:
ComfyUI/user/artemko7v_image_catalog-indexed/<catalog-id>/
catalog.json
<image-id>.png
Back that up yourself - the workflow JSON stores the catalog snapshot, not the image bytes.
Where people get burned
Running the workflow does not save the catalog. This is the one that eats an evening. Queueing stages new uploads for execution and never commits them; Save Changes is the save button. Drag-and-drop onto the node and the file picker both just fill the current draft.
Two copies of the same catalog will fight. Each node owns a snapshot and saves are revision-checked, so editing the catalog from another tab gets a "reload" rejection instead of a silent overwrite. Reload Catalog discards local edits (it asks first); Refresh only re-lists catalogs.
Fields are set in stone. Names and types are read-only after creation (renaming means a new field), names must be unique ignoring case, IMAGE is reserved, and the ceiling is 32 fields including hidden ones. Hidden records get skipped by index selection but stay in the dropdown. Uploads normalize to PNG, capped at 64 MiB each.
It re-runs on every queue. IS_CHANGED returns float("NaN") to defeat ComfyUI's cache, since the catalog lives outside the workflow. Correct - but nothing behind this node is ever cached.
Two last things. With no visible images left the node blocks execution and downstream nodes are simply skipped - a run that "did nothing" is usually an empty or fully hidden catalog. And the pack is young: v0.0.4, one author, no community track record. Small, dependency-free and readable is the right size of risk for a helper node - but read it before you make it a 200-node pipeline's data layer.
Inputs (2)
| Name | Type | Default | Description |
|---|---|---|---|
| image_index | INT | 00–9007199254740991 | — |
| catalog_state | STRING | {} | — |
Outputs (33)
| Name | Type | Description |
|---|---|---|
| IMAGE | IMAGE | — |
| property_1 | * | — |
| property_2 | * | — |
| property_3 | * | — |
| property_4 | * | — |
| property_5 | * | — |
| property_6 | * | — |
| property_7 | * | — |
| property_8 | * | — |
| property_9 | * | — |
| property_10 | * | — |
| property_11 | * | — |
| property_12 | * | — |
| property_13 | * | — |
| property_14 | * | — |
| property_15 | * | — |
| property_16 | * | — |
| property_17 | * | — |
| property_18 | * | — |
| property_19 | * | — |
| property_20 | * | — |
| property_21 | * | — |
| property_22 | * | — |
| property_23 | * | — |
| property_24 | * | — |
| property_25 | * | — |
| property_26 | * | — |
| property_27 | * | — |
| property_28 | * | — |
| property_29 | * | — |
| property_30 | * | — |
| property_31 | * | — |
| property_32 | * | — |