Img Label Tools
Tools to help annotate images for sharing on Reddit, Discord, etc.
Nodes (9)
N labeled grids in one pass — Advanced Stitcher for batch comparisons
Grab reference images from DuckDuckGo — no API key, no account
Turn a pile of images into a labeled comparison grid
Make every image in a batch the same size — without wrecking them
Caption one image the ComfyUI way — Label Image
Load a whole folder of images — single, batch, random, or stepping through one by one
Finally, time one section of your workflow
Start the stopwatch — the other half of Local Timer End
A seedable 'pick N from a list' for prompts and labels
ComfyUI Img Label Tools
Custom nodes for ComfyUI that provide advanced image processing and labeling capabilities for creating organized image arrays and equalizing image dimensions.
Every widget has a hover tooltip that explains what it does. This README covers the same options in more detail.
Installation
Via ComfyUI Manager (Recommended)
- Open ComfyUI Manager
- Search for "Img Label Tools"
- Click Install
Manual Installation
-
Navigate to your ComfyUI custom_nodes directory:
cd ComfyUI/custom_nodes/ -
Clone this repository:
git clone https://github.com/rjgoif/ComfyUI-Img-Label-Tools.git -
Restart ComfyUI
Nodes at a glance
All nodes are in the Image Label Tools category.
| Node | What it does | | --- | --- | | Image Equalizer | Brings a set of images to one common size (largest, smallest, or a chosen image). | | Image Array | Arranges images into a labeled grid and returns one combined image. | | Label Image | Adds a text label to a single image. | | Advanced Stitcher | Splits images into groups and stitches each group into its own labeled grid. | | Random Subset | Picks a random subset of the lines in a block of text. | | Load Images From Folder(s) | Loads images from a folder with filtering, stepping, limiting and sorting. | | DuckDuckGo img search | Downloads images from DuckDuckGo image search. | | Local Timer Start / End | Measures how long the nodes between them take to run. |
Nodes
Image Equalizer
Equalizes multiple images to matching dimensions. Every image from every connected batch or list is treated as one set, in input order.
Inputs:
images- List or batch of images to equalize
Parameters:
size_mode- Which size every image is brought to:grow- Match the largest width and height among the images (default)shrink- Match the smallest width and height among the imagesmatch- Match the size of image numbermatch_N
match_N- Only used whensize_modeismatch(default 1, max 9999). Which image sets the target size, counting from 1 in input order. If there are fewer images than this number, the last image is used, so a large value such as9999always means the last image.upscale_method- Resampling method used whenever an image is resized (nearest-exact,bilinear,area,bicubic,lanczos)keep_proportion- How each image is fitted to the target size:pad- Scale to fit inside the target, then add padding to reach the exact size (default)stretch- Resize to the exact target size, ignoring aspect ratioresize- Scale to fit inside the target with no padding. Results may not all be the same size, but each fits in the target bounding box.crop- Scale to fill the target and cut off the overflowtotal_pixels- Scale each image, keeping its own aspect ratio, to the same total pixel count as the target. Results may not all be the same size, depending on aspect ratio.
pad_color- Padding color. Only used whenkeep_proportionispad.black,white,gray- Solid colorsaverage- Gamma-corrected average color of the resized imageaverage_edge- Gamma-corrected average color of the outer 5% border of the resized image
crop_position-center,top,bottom,leftorright.- With
pad: where the image sits inside the padded frame. The padding goes on the opposite side. - With
crop: which part of the image is kept. topandbottomonly matter when height is padded or cropped.leftandrightonly matter when width is.- Ignored by
stretch,resizeandtotal_pixels.
- With
Outputs:
images- A list of the resized images, in input order. All images share one size, except withkeep_proportionset toresizeortotal_pixels.
Use Cases:
- Prepare images for array display (primary use)
- Prepare images for batch processing without losing data
- Create uniform image sets for training data (one of many nodes that can)
- Bring every image to the size of one reference image (
size_mode: match)
Image Array
Creates organized grids/arrays of images with optional text labels. Images are first resized to a common size, then labeled, and finally arranged in a grid. Images always fill the grid left to right, then top to bottom, whatever the shape.
Inputs:
images- List or batch of images to arrange. Every image from every connected batch or list is used, in input order.label_input(optional) - Dynamic label input (string, number, or list). When connected, it replaces thelabelsbox.
Parameters:
Layout:
background- Canvas color (whiteorblack). It is also used for the gaps fromspacingand for padding added bysize_method. Label boxes use the opposite color, with their text in the background color.shape- Array layout:horizontal- Single row (default)vertical- Single columnsquare- N×M grid closest to square (minimizes blank cells)smart_square- Optimizes for 1:1 aspect ratio considering image dimensionssmart_landscape- Optimizes for 3:2 aspect ratio considering image dimensionssmart_portrait- Optimizes for 2:3 aspect ratio considering image dimensionsforce_rows- Output hasforced_Nrows. Columns are worked out from the image count (seeforced_N).force_cols- Output hasforced_Ncolumns. Rows are worked out from the image count (seeforced_N).
smart_ratio- Custom W:H target for smart layout. When filled, overrides the shape picklist and runs the grid search against this ratio. Accepts16:9,16/9,1.78,3x1,3W x 1H, etc. Leave blank to use the shape picklist.force_rows/force_colstake priority oversmart_ratio.forced_N- Only used whenshapeisforce_rowsorforce_cols(default 1). Sets the number of rows or columns in the output. Fill order never changes: images always fill left to right, then top to bottom, so 14 images withforce_rows= 3 orforce_cols= 5 give the same 3×5 grid. Capped at the image count. Withforce_rows, if the exact row count can't be reached without an empty row (for example 14 images with 6 rows), the closest row count without one is used (5 rows).
Sizing:
resize_any- ON: resize all images to one common size before arranging. OFF: keep native sizes; each grid cell is as large as the largest image, and smaller images are centered in their cell.size_guide- Target size whenresize_anyis ON: thelargestorsmallestimage, ormatchto use the size of image numbermatch_Nmatch_N- Only used whensize_guideismatch(default 1, max 9999). Which image sets the target size, counting from 1 in input order. If there are fewer images than this number, the last image is used, so a large value such as9999always means the last image.size_method- How each image is fitted to the target size. It only comes into play if the input images are different sizes.pad small dim- Scale to fit inside the target and fill the rest with the background color (default)stretch- Resize to the exact target size, ignoring aspect ratiocrop_center- Scale to fill the target, then cut the overflow equally from both sidescrop large dim- Scale to fit inside the target with no padding and no cropping. One side matches the target and the other is smaller, so image sizes can differ.
Labels:
labels- Multiline text box for labels, one per image in order. See Label text format.label_end- What happens when there are more images than labels:loop- Start over from the first label (default)end- Images after the last label get a blank label. The label space is still reserved.
label_location- Where each label goes relative to its image:top,bottom,left_hor,right_hor(horizontal text beside the image) orleft_vert,right_vert(rotated text beside the image). Every image gets the same amount of label space, sized for the longest label, so cells stay aligned.label_size- Font size in pixels (0-200, default 32). Set to 0 to turn labels off completely; no label space is added.font- Font selection from the ComfyUIfontsdirectory. See Font Setup.
Spacing:
spacing- Gap in pixels added around every image, after its label (0-100, default 5). It is filled with the background color, so it shows up as a gap. The gap between two neighbors is double this value.
Outputs:
array- The finished grid as one imageimages- List of the individual images after resizing and labeling, before spacing is added
Label text format
Labels can be provided in multiple ways:
-
Multi-line labels: Use
\nwithin a label for line breaks in the textImage 1 Image 2\nLine 2 Image 3This creates 3 labels, where the second label displays on two lines.
-
Semicolon-separated:
Image 1; Image 2; Image 3 -
Dynamic input: Connect string, number, or list output from another node to
label_input. It replaces thelabelsbox. -
Numbers: Automatically formatted (decimals truncated to 5 places, trailing zeros removed)
Note: Actual newlines (pressing Enter) separate different labels. Use \n (backslash-n) for line breaks within a single label.
Use Cases:
- Image galleries/comparisons (for Reddit, etc)
- Manual XYZ stuff.
Label Image
Adds a text label to a single image. If a batch is connected, every frame gets the same label. The image gets larger to make room for the label.
Inputs:
image- Image to labellabel_input(optional) - Label text from another node. When connected, it replaces the text box.
Parameters:
label- Free text box (multiline). Press Enter for a new line.label_location- Where to place the label (top,bottom,left_vert,left_hor,right_vert,right_hor)._horputs horizontal text beside the image and_vertputs rotated text beside it.label_size- Font size in pixels (1-200, default 32)font- Font selection from the ComfyUIfontsdirectory. See Font Setup.label_style- Color scheme, written as text color on label box color:white on black(default)black on whitewhite on dark grayblack on light gray
Outputs:
image- Labeled image
Advanced Stitcher
Splits an image list into groups, stitches each group into a labeled grid, and returns the results as a list of images. Primary use case is interleaved grouping: comparing every Nth image across a batch side by side.
Its sizing, layout and label options work like the ones in Image Array. The differences are that label colors come from label_style (Image Array derives them from background), background defaults to black, and label_end has different options (see below).
Inputs:
images- Image list. Every image from every connected batch or list is used, in input order.label_input(optional) - Label text from another node. When connected, it replaces thelabelsbox.
Parameters:
Grouping:
N- Group count or group size (default 1), depending ongroup_modegroup_mode:every_N- Interleaved: produces N groups, each containing every Nth image. With 12 images and N=3: groups are [0,3,6,9], [1,4,7,10], [2,5,8,11]. Leftover images fill front-to-back.length_N- Chunked: sequential groups of N images. With 12 images and N=3: groups are [0,1,2], [3,4,5], [6,7,8], [9,10,11]. Short final groups are padded with a blank filler image.
Labels:
labels- Multiline text with the same format as Image Array (one per line or semicolon-separated,\nfor a line break inside a label). The label list restarts independently for each group. If K labels < group size, trailing slots are blank or repeat the last label depending onlabel_end.label_end:blank- Trailing slots past the end of the label list are emptyrepeat_last- Trailing slots repeat the final label
label_location,label_size,font- Same as Image Arraylabel_style- Color scheme, written as text color on label box color (same 4 options as Label Image; defaultwhite on black)
Layout & Sizing:
shape- Grid layout for each stitched group (same options as Image Array, includingforce_rows/force_cols; defaulthorizontal)smart_ratio- Custom W:H target, same format as Image Array (force_rows/force_colstake priority)forced_N- Same as Image Array; sets the rows or columns of each stitched group whenshapeisforce_rowsorforce_cols(default 1)background- Canvas color (black/white). Also used for blank filler slots, for padding added bysize_method, and for the gaps fromspacing.resize_any- ON: resize the images in each group to one common size before stitching. OFF: keep native sizes.size_guide-largestorsmallesttarget whenresize_anyis ON, ormatchto use the size of image numbermatch_Nin each groupmatch_N- Only used whensize_guideismatch(default 1, max 9999). Which image in each group sets the target size, counting from 1 in group order. If a group has fewer images than this number, the last image in that group is used (blank filler slots are skipped), so a large value such as9999always means the last image.size_method- Same 4 options as Image Arraypad_axis- Only used whenresize_anyis ON. Which dimension is made equal across each group:both- Same width and height (default)height_only- Same height; each image keeps its own width. Ideal for horizontal stitching of variable-width images.width_only- Same width; each image keeps its own height. Ideal for vertical stitching.
spacing- Gap in pixels added around every image, after its label (0-100, default 5), in the background color
Outputs:
stitched_groups- List of stitched images, one per group
Random Subset
Picks a random subset of the lines in a block of text. Same seed and settings always give the same picks.
Parameters:
input_text- The items to choose from, one per line. Blank lines are ignored.num_to_pick- How many items to pick. Without replacement this is capped at the number of items.with_replacement- ON: the same item can be picked more than once, andnum_to_pickis not capped. OFF: each item is picked at most once (default).random_order- ON: shuffle the picked items one more time before output (default). OFF: skip that extra shuffle; items come out in the order they were drawn. This is not the original list order, except when every item is picked.string_delimiter- Text placed between items inmerged_string. Type\nfor a new line (default).seed- Random seed
Outputs:
string_list- The picked items as a list, one entry per itemmerged_string- All picked items joined into one string withstring_delimiterpick_indices- Position of each picked item in the input list, counting from 0 (blank lines are not counted)
Load Images From Folder(s)
Loads images from a folder with filtering, stepping, limiting and sorting. Supported file types: png, jpg, jpeg, gif, tiff, tif, webp, bmp. Images are converted to RGB and rotated according to their EXIF orientation.
The order of operations is: find files, filter, sort with select_sort, keep every every_nth image, apply limit, then re-order with output_sort.
Parameters:
folder- Root folder to searchsubdirectories- ON: also search subfolders offolder. OFF: only the folder itself (default).filter- Text or regex pattern to match against file names. Leave blank to keep every supported image.filter_type- Howfilteris matched:contains(default),starts with,ends withorregex. A regex is searched anywhere in the name, and an invalid pattern matches nothing.filter_case_sensitive- Whether the filter match is case sensitive (default off)filter_include_extension- ON: match the filter against the full file name including its extension. OFF: match only the name without extension (default).select_sort- Order the filtered pool is sorted into beforeevery_nandlimitare applied: name, total pixels, aspect ratio or date modified (each ascending or descending), orrandomevery_n- Keep every Nth image from the filtered and sorted pool, starting with the first. 1 keeps every image, 2 keeps every other image, and so on.limit- Maximum number of images to keep afterevery_nstepping. 0 means no limit.output_sort- Order applied to the final selection for output.nonekeeps the order from theevery_n/limitstep. Other options are the same asselect_sortplus date created.seed- Random seed, used wheneverselect_sortoroutput_sortisrandom(the two shuffles are independent)
Outputs (all lists except the two counts):
images- The loaded images. Each can be a different size. If nothing is found, a single 1×1 black image.file_paths- Full path of each loaded imagefilenames- File name with extensionfilenames_no_ext- File name without extensionsubdirs- Each image's folder relative to the root folder, written with backslashes and wrapped in backslashes:\for files directly in the root,\vacation\for a subfolderdirectory- Full folder path of each image (root plussubdirs), ending with a backslash, without the file name.directory+filenamesrebuilds the full path.filtered_count- How many files matched the filter, beforeevery_nandlimitoutput_count- How many images were actually loaded
DuckDuckGo img search
Downloads images from DuckDuckGo image search.
Requires: pip install duckduckgo-search requests
Parameters:
query- Search textstart- How many results to skip from the top (0 starts at the first result)num_results- How many results to return, counted after skippingstartoutput_type:list- Each image is returned separately at its own size (default)batch- All images are padded with black to the largest width and height and returned as one batch
region,safe_search,size,color,type_image,layout,license_image,ai_images- Search filters. These are not applied yet. The current code only sends the query text to DuckDuckGo, so changing them has no effect.
Outputs:
image(s)- The downloaded images. An image that fails to download becomes a 64×64 black placeholder, so positions still matchurl(s).url(s)- Source URL of each image, in the same order
If the search returns nothing, the node stops with an error.
Local Timer Start and Local Timer End
Measure how long the nodes between them take to run. Each Start/End pair works independently, so you can time several sections of a workflow.
Local Timer Start: Place it just before the node(s) you want to time. Wire your workflow value into passthrough; it comes out unchanged, together with a timer output. The node always re-runs, so the timestamp is fresh each time.
Local Timer End: Wire timer from Local Timer Start into its timer input, and the value coming out of the timed section into passthrough.
Parameters (Local Timer End):
format:h m s- Text like3h 5m 2sor34s(zero parts omitted) (default)hh:mm:ss- Text like03:05:02h,m,s- A number of hours, minutes or seconds, rounded to 2 decimals
Outputs (Local Timer End):
passthrough- The input value, unchangedtime_string- Elapsed time as text (empty forh,mands)time_float- Elapsed time as a number in the unit chosen byformat(0.0 for the text formats)
Examples
Eventually...
Requirements
- ComfyUI (latest version recommended)
- Python 3.8+
- Pillow (PIL)
- PyTorch
duckduckgo-searchandrequests(only for the DuckDuckGo img search node)
Tips
Image Equalizer:
- Use
average_edgepadding for seamless borders that match image content - Use
grow+padfor lossless size normalization - Use
shrink+cropto create uniform thumbnails - Use
matchwithmatch_Nto bring every image to the size of one chosen reference image
Image Array:
- Use
smart_squarefor photo galleries with mixed portrait/landscape images - Set
spacingto 5-10 pixels for clean visual separation - Place labels on
bottomortopfor easier reading - Use
left_vertorright_vertfor space-efficient labeling - For dynamic labels, connect output from other nodes like counters or text processors
smart_ratioaccepts most common formats:16:9,16/9,1.78,3x1,3W x 1H- Use
force_colswithforced_Nfor a fixed-width grid of any length (for example 4 columns), orforce_rowsfor a fixed-height grid - Set
size_guidetomatchandmatch_Nto 9999 to size every image to the last one
Advanced Stitcher:
- Use
every_Ngrouping to compare corresponding frames across N different generation runs side by side - Use
pad_axis: height_onlywith horizontal stitching when input images have different widths but matching heights. It avoids width padding and keeps each image at its native width - With
resize_anyOFF, images are placed at native sizes; the canvas grows to fit without padding
Load Images From Folder(s):
- Use
every_nwithselect_sortto sample evenly across a folder, orselect_sort: randomwithlimitfor a random sample - Connect
filenames_no_exttolabel_inputon Image Array to label each image with its own file name
Font Setup
For custom fonts:
- Create a
fontsdirectory in your ComfyUI installation root - Place TrueType (.ttf) font files in this directory
- Restart ComfyUI - fonts will appear in the dropdown
If no fonts directory exists, the dropdown only offers arial.ttf, which is loaded from C:/Windows/Fonts/Arial.ttf. If a font cannot be loaded (for example Arial on a non-Windows system), a small built-in font is used and label_size has no effect.
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
Credits
- Image Equalizer inspired by KJNodes by GitHub user kijai
- Labels for Image Array inspired by Mikey Nodes by GitHub user bash-j
- Created for the ComfyUI community
License
MIT License - see LICENSE file for details
Support
If you encounter any issues or have suggestions, please open an issue on GitHub: https://github.com/rjgoif/ComfyUI-Img-Label-Tools/issues