Extensions/Image Catalog Indexed
ComfyUI Extension

Image Catalog Indexed

ComfyUI node that lets the user store indexed collection of images with associated properties.

By ArtemKo7v·Created 23 days ago·Updated a day ago· 4
ArtemKo7v/ComfyUI-ImageCatalogIndexed
Nodes1
On cloudLocal install
Categoryimage/catalog
Stars4
Updateda day ago
Readme

ComfyUI-ImageCatalogIndexed

A ComfyUI custom node for persistent image catalogs with a typed property schema. Select an image by index and output its IMAGE tensor and named property values.

Installation

Place this repository in ComfyUI/custom_nodes/ComfyUI-ImageCatalogIndexed, restart ComfyUI, and refresh the browser. Add Image Catalog Indexed from image/catalog. Python 3.10 or newer is required. The runtime uses ComfyUI's existing PyTorch, NumPy, Pillow, and aiohttp dependencies; no model downloads are needed. There are no additional runtime packages to install, so this node does not need a requirements.txt. requirements-dev.txt is only for development and CI.

Create a catalog

  1. Leave Create a new Image Catalog selected and enter a Catalog name.
  2. Enter property names and choose their types. Filling the last row adds another row, up to 32 properties. Empty rows are ignored; a schema may have no properties.
  3. Click Create Now. The catalog becomes active in add-image mode.
  4. Choose a local image and enter its property values. Use Add Image to prepare more images. Save Changes saves all images and properties without running the workflow; running the workflow alone never saves the catalog.

Catalog names must be unique, ignoring case. Property names must also be unique, and IMAGE is reserved for the image output. Use Edit to manage fields after creation.

| Property type | Editor | Output type | Default | | --- | --- | --- | --- | | String | Single line | STRING | Empty string | | Text | Multiple lines | STRING | Empty string | | Integer | Integer field | INT | 0 | | Boolean | Checkbox | BOOLEAN | false |

Integers must be within JavaScript's safe integer range, from -9007199254740991 to 9007199254740991.

Select images and run

The image dropdown and preview select a record from the active catalog. Choosing a visible record updates image_index. This is the only input that can be connected to another node; images and property editors are not input sockets.

Dropdown labels show the filename, without record hashes. If the schema has a name field with a nonempty value, the label is name [filename]; the name is limited to 32 characters followed by an ellipsis when longer. Local name edits update the label immediately, including drafts. Empty names fall back to the filename, and hidden records retain their (hidden) marker.

The selector heading shows Image (N/NN): the displayed image's one-based position and the total number of local catalog images, including hidden records and drafts with selected files. Empty drafts are not counted and show position zero. The counter updates when selecting, adding, deleting, or reloading images. Arrow buttons on either side of the preview navigate this list without wrapping. They are vertically centered; the previous arrow is absent on the first image, the next arrow on the last, and both are absent for a single image.

The catalog editor expands with the node and fills the remaining height. It has a minimum height of 420 px and scrolls internally when its contents do not fit.

image_index starts at zero and addresses the ordered list of visible records. Out-of-range indices wrap around. Index after queue is a regular node widget directly below image_index, like a seed control. It is available before a catalog is selected and keeps its mode when switching catalogs. It controls the next run:

  • fixed: keep the current index.
  • increment: advance by one, wrapping from the last image to the first.
  • decrement: go back by one, wrapping from the first image to the last.
  • randomize: select a random visible index; repeats are allowed.

The browser advances the index after a prompt is successfully queued, including each item in a batch. A later execution error does not roll back this advance. When image_index is connected, its incoming value takes precedence and automatic index control is disabled. After execution, the preview follows that result. Manual edits always belong to the record shown when they were entered, even when the connected index selects a different output image.

The first output is an RGB IMAGE tensor shaped [1, height, width, 3] with values between zero and one. Following outputs have the property names, types, and order from the schema. Alpha is retained in the stored PNG but is not a separate output. For animated images, only the first frame is stored. EXIF orientation is applied.

Edit, hide, and delete

The editor has two bordered blocks. The upper block contains Catalog, with Refresh to its right, and the catalog actions. Creation and field-editing forms open inside this block. The lower image block appears only when a catalog is selected. It contains the image selector, preview, properties, and Hidden.

Each node owns a local catalog snapshot stored in the workflow. All property, visibility, field, and image-list changes affect workflow outputs immediately, without writing the server JSON. Switching images retains all pending changes.

The left-aligned Hidden checkbox precedes its label and makes the preview and fields translucent and read-only. Hidden records are skipped by index selection but remain in the dropdown for restoration. Clear Hidden to include the record again.

The red Delete button on the right asks for confirmation and removes the displayed image from the local catalog. The server record and image file remain until Save Changes. Deleting a new draft removes only that draft.

Replace Image below an existing image's preview opens the file picker and drag-and-drop area in place of the preview. Cancel Replacement closes the picker without changing the image. Choosing a file replaces only the image and its display filename: the record ID, position, properties, and catalog count stay the same. Workflow execution uses the replacement immediately, while the saved image remains unchanged until Save Changes. Saving publishes the replacement atomically before removing the old file. A failed save keeps the original intact. Unhide a hidden record before replacing its image. As with new drafts, unsaved replacement files must be selected again after restoring a workflow.

Below the divider, Add Image and Save Changes are aligned to the left. Add Image starts another draft; the image dropdown lets you switch between drafts and stored records. Blank drafts without files are ignored. The file picker sits inside a dashed drop area with 20 px padding. Drag one image into this area, or use the file picker. The area highlights while dragging; a drop updates the current draft without importing a workflow or saving to the server. Save Changes asks to save all changes for all images and fields, stages new files, and commits the complete catalog through the API. It also permanently removes files for deleted records. No workflow run is necessary.

Workflow queueing stages new files as needed for execution, but never adds them to the saved catalog. An unconnected index outputs the displayed new image on its first run; subsequent batch items follow the index mode. A connected index always takes precedence. The node outputs one image per execution. If no visible images remain, downstream nodes are skipped.

Uploads are limited to 64 MiB per file and converted to PNG. Save operations use atomic JSON replacement and roll back new image copies if saving fails. A retry does not duplicate images. Version checks reject a stale save from another node or browser tab; local edits remain available. Copy your local edits or save the workflow before using Reload to resolve a conflict.

Refresh updates only the available catalog list. Reload discards local changes after confirmation and loads the server version. Switching catalogs also asks before discarding local changes.

Delete remains a separate, immediate operation: after confirmation it permanently deletes the catalog JSON, its images, and its staged uploads. Creation and ZIP import also write server catalogs immediately. Other catalogs are not affected.

Catalog fields

Edit opens a separate editor for the selected catalog's schema. Use Add property to append a field, Remove property to remove one, and Hidden to hide a field from image forms. Up to 32 fields are supported, including hidden fields. Existing field names and types are read-only; create a new field when a different name or type is needed.

Apply Fields updates only this node's local schema; Save Changes persists it together with all image edits. New fields receive their type's default value in every record and pending draft. Removing a field asks for confirmation and removes its local values; Cancel discards edits not yet applied.

Hidden fields retain their values and named outputs. Clear Hidden in the editor to show them again. Removing a field removes its output; connections to remaining fields are preserved when their slots shift. Other nodes retain their own workflow snapshots rather than receiving unsolicited schema changes.

Finish field editing with Apply Fields or Cancel before saving or exporting.

Export and import

Export downloads a ZIP containing the server's exact catalog.json and its saved PNG files at the archive root, including hidden records and fields. If there are local changes, a dialog offers Save and Export, Export Saved Version, or Cancel. Exporting the saved version leaves local changes intact. Saving first commits all local changes, including deleted images, before export.

Import is available when Create a new Image Catalog is selected. Choose an exported ZIP to import its data as a separate catalog. The imported catalog becomes active. Identifiers are regenerated and existing catalogs are never overwritten. Name collisions receive an (imported) suffix, numbered when necessary. A failed import does not publish a partial catalog.

To synchronize additions from another ComfyUI instance, select the existing catalog and click Import Additions, then choose that instance's exported ZIP. New records are appended in archive order, including hidden images and their property values. Existing images, values, visibility, order, and local records absent from the archive are retained. Reimporting the same ZIP adds no duplicates; the status reports how many images were added or skipped. This operation saves directly on the server. Save pending local changes and finish field editing first. Other nodes keep their workflow snapshots; use Reload to see additions.

Catalogs and records retain synchronization identifiers across export/import, even though each fresh import gets new storage identifiers. The archive must belong to the same catalog family, and properties present in both catalogs must have the same type. Field order and visibility can differ. If the archive contains additional properties, a dialog lists their names and types and offers Cancel, Import Without New Fields, or Extend Catalog and Import. No changes are saved until you choose an import option. Ignoring new fields imports only values for existing local fields. Extending appends the new fields, retains their values on new images, and fills existing images with the type defaults (empty string, zero, or false). Existing image values are otherwise retained. Extension also works when all archive images already exist; the catalog still supports a maximum of 32 fields. If local fields are missing from the archive, the dialog lists them and offers Cancel or Import With Defaults. The current schema and existing images are retained; new images receive empty strings for String/Text, zero for Integer, and false for Boolean in the missing fields. If there are both new and missing fields, the same dialog lists both groups and offers the new-field choices above; missing local fields receive defaults with either import option. Older archives with original catalog/record IDs are supported. Copies imported by older versions that regenerated IDs without retaining their origin cannot be matched automatically; transfer a fresh export with this version to establish a shared catalog family. Deletions and edits to existing records are not synchronized. An image deleted locally can return if it is still present in a later archive.

Import accepts ZIP files up to 512 MiB, with up to 10,000 images, 16 MiB of JSON, and 2 GiB of total unpacked data. Files must match the JSON manifest and contain valid PNG images. Nested paths, symbolic links, duplicate members, encrypted archives, and missing image files are rejected. These limits apply to import; very large exports may need to be split into smaller catalogs before importing.

Storage and workflow persistence

Files live under the configured ComfyUI user directory:

user/artemko7v_image_catalog-indexed/
  <catalog-id>/
    catalog.json
    <image-id>.png
  .staging/
    <upload-token>.json
    <upload-token>.png

They do not appear in the normal Load Image list. Original filenames are display labels; generated identifiers keep storage paths independent of names. Catalog JSON contains the schema, ordered entries, record revisions, and recent operation identifiers. Writes replace JSON atomically. Concurrent stale edits are rejected with a message to reload, rather than silently overwriting newer values. One ComfyUI process should own a storage directory.

Uploaded staging files are removed after a successful save. Abandoned uploads expire after seven days and are cleaned during later uploads. Workflow execution, including downstream failures, never changes the saved catalog.

Workflow JSON preserves the full catalog metadata snapshot, schema/output layout, index mode, selected record, pending drafts, and property edits. Restoring a workflow does not replace that snapshot with the server's latest JSON. It does not embed image bytes: back up storage separately. Unsaved local files must be selected again after restoring a workflow; saved images load from the server. If another editor has deleted a referenced server image, the workflow cannot recover its bytes.

API clients can execute a serialized catalog_state containing catalog_id and client_catalog (the complete metadata snapshot). They must stage new files explicitly and supply their indices. Use POST /artemko7v/image-catalog/catalogs/{id}/save with catalog, expected_revision, and a unique 32-character lowercase hexadecimal operation_id to save. Legacy workflow snapshots remain executable, but no longer save on execution. The node remains an output node so it can execute without connected outputs.

Development checks

Storage and index tests need only Python and Node.js 22 or newer:

python -m unittest discover -s tests -v
node --test tests/catalog_model.test.mjs

HTTP integration tests run when Pillow, NumPy, and aiohttp are installed; otherwise they are skipped. Install all test dependencies to run the complete suite. The browser smoke test uses Playwright's Chromium by default:

python -m pip install -r requirements-dev.txt
python -m playwright install chromium
python -m unittest discover -s tests -v
node --test tests/catalog_model.test.mjs
python tests/browser_smoke.py

On Linux, use python -m playwright install --with-deps chromium to also install browser system dependencies. To use an already installed Microsoft Edge instead, set PLAYWRIGHT_CHANNEL=msedge in the environment. The smoke screenshot is saved to test-results/catalog-browser-smoke.png.

GitHub Actions runs Python tests on 3.10, 3.12, and 3.13, JavaScript tests on Node.js 22, and the Chromium smoke test. CI installs all integration dependencies. Registry publishing runs the same checks first and publishes only from main. It is triggered by changes to pyproject.toml or manually through Actions and requires the COMFY_REGISTRY_TOKEN repository secret. Increment project.version before publishing a new registry version.

The browser test uses temporary catalogs, the real extension JavaScript and HTTP handlers, and a small ComfyUI host substitute. It checks index control placement, multiple drafts, deferred uploads, previews, typed outputs, saving, restoration, hiding, schema editing, ZIP export/import, and deletion. PyTorch is substituted with NumPy in this harness. It does not replace a smoke test in an actual ComfyUI installation, including graph links and the frontend's node renderer.

The integration follows the upstream node properties and JavaScript extension APIs.