Nodes/comfyui-AGSoft/🖼️AGSoft Contact Sheet
ComfyUI Node

🖼️AGSoft Contact Sheet

Turn a 24-image KSampler sweep into one image you can actually read

By Art-xmaster·Created about a year ago·Updated about 15 hours ago· 27
🖼️AGSoft Contact Sheet
  • images
  • sheet
  • labeled
current_str
columns0
font_size24
padding8
positiontop_left
text_opacity1.00
box_opacity0.60
text_colorwhite
box_colorblack
box_radius10

If you have ever run a 24-item sampler sweep, you already know the problem: the batch is sitting in your temp folder as 24 files named ComfyUI_00041_ through ComfyUI_00064_, and you have no idea which one was steps=12 and which was steps=16. 🖼️AGSoft Contact Sheet exists to kill that step. It burns a label into each frame and pastes the whole batch into one NxM grid, so the sweep is a single image you can scroll, save, or drop into Discord.

What it actually does

Two things, in this order. First it labels: it takes the batch on images, splits current_str on newlines, and burns line N into frame N. Second it grids: it lays the labeled frames out into a contact sheet and returns that as one IMAGE.

The labeling is plain Pillow compositing, not a magic text engine. For each frame it draws a rounded rectangle at your chosen corner (box_color, box_opacity, box_radius), alpha-composites it over the frame, then draws the text on top (text_color, text_opacity). Box and text have separate opacity, which is the thing most label nodes get wrong - with box_opacity at its 0.6 default, white text stays legible over a bright frame, and setting it to 0 gives you a bare label with no plate behind it.

The grid pass is where the layout decisions happen. columns = 0 means auto, which the source computes as ceil(sqrt(n)) - so 9 frames become 3×3 and 16 become 4×4. Cell size is the largest frame in the batch, the canvas is filled black, and every frame is pasted at its native size with padding between cells.

You get two outputs, and the second one is the useful surprise: sheet (the single grid image) and labeled (the same batch, labels burned in, original order). So you can preview the sheet for eyeballing while still piping labeled into a video node or Save Image Plus with the parameter text baked into the pixels.

The inputs worth touching

Everything except images is optional, and three of them do 90% of the work:

  • images - the batch, typically straight off AGSoft KSampler's decoded images output.
  • current_str - the string output of options_single, options_dual or options_lora. Wire it here and line N lands on frame N. Leave it unconnected and you still get a clean grid, just no captions.
  • columns - 0 for auto, or set it explicitly (e.g. 4) when you want a fixed row width for a post. Max 16.

Then font_size (24 default), padding, position (six corner/edge choices), and the four look-and-feel knobs. box_radius is clamped to half the box size, so cranking it to 128 just gives you a pill.

Install

Same as the rest of the pack, and this node needs nothing extra - no models, no downloads:

cd ComfyUI/custom_nodes
git clone https://github.com/Art-xmaster/comfyui-AGSoft
# restart ComfyUI

Or in ComfyUI Manager, search comfyui-AGSoft and install. The pack's requirements.txt is numpy, opencv-python and translators; none of it is this node, and all of it is normally already present in a working ComfyUI.

Where people get burned

Captions missing. Either current_str isn't connected, or it's connected to the wrong thing. It wants the current_str socket of an options node, not the KSampler's options output - that one carries a dict of the last run, not one line per frame.

Fewer lines than frames. The code reads lines[idx] if idx < len(lines), so frames past the last line come out unlabeled. Silent, not an error. If your series was in current mode you'll only have one line, and only frame 1 gets a caption.

Tiny, unreadable labels on Linux boxes and minimal Docker images. The node looks for arial.ttf or DejaVuSans.ttf on the system (plus the Windows font path) and falls back to Pillow's default bitmap font if neither exists - and the default font ignores font_size entirely. If your labels are legible-but-microscopic, install a font rather than turning the size up:

sudo apt install fonts-dejavu-core     # Debian/Ubuntu

Black gaps in the grid. The canvas is filled black and each frame is pasted at its own size, so a batch with mixed resolutions leaves holes. Keep one resolution per sweep.

Nothing loads at all? The pack's __init__.py imports every .py file in the folder and skips any module that raises on import, logging Import error in module '<name>'. If the node isn't in the menu, check the ComfyUI console - the missing node will be named there.

CategoryAGSoft/🧩KSampler

Inputs (11)

NameTypeDefaultDescription
imagesIMAGEImage batch (e.g. series result from AGSoft KSampler). --- Батч изображений (например результат серии из AGSoft KSampler).
current_stroptSTRINGConnect the current_str output of options_single / options_dual / options_lora here: one line per frame (line N is burned into frame N). If not connected or empty — no labels. --- Подключи сюда выход current_str нод options_single / options_dual / options_lora: по одной строке на кадр (строка N вжигается в кадр N). Не подключено или пусто — без подписей.
columnsoptINT00–16Grid columns; 0 = auto (square-ish). --- Колонок в сетке; 0 = авто (примерно квадрат).
font_sizeoptINT248–128Label font size. --- Размер шрифта подписи.
paddingoptINT80–64Grid padding and label inset from the frame edge. --- Отступы сетки и отступ подписи от края кадра.
positionoptCOMBOtop_leftLabel position: top or bottom, left / center / right. --- Позиция подписи: сверху или снизу, слева / по центру / справа.
text_opacityoptFLOAT1.000–1Text opacity (0 = invisible, 1 = solid). --- Прозрачность текста (0 = невидимый, 1 = сплошной).
box_opacityoptFLOAT0.600–1Background box opacity behind the text (0 = no box). --- Прозрачность плашки под текстом (0 = без плашки).
text_coloroptCOMBOwhiteText color preset (24 templates). --- Шаблон цвета текста (24 варианта).
box_coloroptCOMBOblackBackground box color preset (24 templates). --- Шаблон цвета плашки (24 варианта).
box_radiusoptINT100–128Box corner radius in pixels; 0 = straight corners. Auto-clamped to half of the box size. --- Радиус скругления углов плашки в пикселях; 0 = прямые углы. Автоматически ограничивается половиной размера плашки.

Outputs (2)

NameTypeDescription
sheetIMAGESingle NxM contact sheet image. Одно изображение-сетка NxM.
labeledIMAGEBatch with labels burned in (same order). Батч с вжжёнными подписями (тот же порядок).