Nodes/ComfyUI-Majoor-ImageOps/〽️ ImageOps Text
ComfyUI Node

〽️ ImageOps Text

Watermarks, subtitles, and title cards on every frame — no extra tools

By MajoorWaldi·Created 8 months ago·Updated 8 days ago· 11
〽️ ImageOps Text
  • color
  • stroke_color
  • image
  • mask
  • image
  • mask
bypassfalse
textImageOps Text
x0.500
y0.500
font_size64
opacity1.00
aligncenter
line_spacing4
stroke_width0
invert_maskfalse
font_path

Eventually you'll want words on your images, and it won't be the fun kind. Watermarking AI output before posting is standard practice in this community, and if you're making video you'll need subtitles or a title card burned into the frames. ImageOps Text does all of that inside the graph: multiline text, a real font, stroke/outline, alignment, opacity - composited over an image or every frame of a batch in one go.

It's the text-overlay node from the MajoorWaldi ComfyUI-Majoor-ImageOps pack. Core ComfyUI has famously nothing for text, and the classic workaround (WAS Node Suite's text nodes) is a heavier install if all you want is a clean burn-in. What this node adds on top of the basics is batch awareness - the pack treats every IMAGE input as frames, so a 120-frame animation gets its captions on all 120 frames, consistently, in a single pass.

How it works

Under the hood it's the same approach a compositor would use manually: render the text into a transparent RGBA overlay, then alpha-composite it over the source. The rendering is done with Pillow's multiline text drawing - no GPU involved - so it's deterministic and easy to reason about. The x / y inputs are normalized (0.0–1.0, top-left origin), and default to 0.5, 0.5, meaning the text anchor sits mid-frame. align handles left/center/right on the text itself.

Fonts are the thing most people hit first. If you leave font_path empty, the node tries arial.ttf, then DejaVuSans.ttf (present on most Linux installs), then falls back to Pillow's default bitmap-ish font - which looks like it sounds. For anything presentable, give it a path to a real .ttf on disk. It's a plain string input, so you can wire a path from a text node and switch fonts at runtime.

Inputs that matter

  • text - multiline; hit Enter for a new line. The default string is "ImageOps Text", so your first run will stamp that across your image. Change it first.
  • x / y - normalized anchor position. Remember the center default; drag on the live preview or set 0.02, 0.02 for a top-left corner watermark.
  • font_size (1–512 px) and color - the color swatch has the pack's eyedropper, so you can pick a color off any visible preview.
  • opacity - text alpha. Set it to 0 and the node is a pure passthrough.
  • stroke_width / stroke_color - an outline, which is the difference between a title that reads over a busy background and one that doesn't.
  • font_path - see above.
  • mask - an effect mask that restricts where the text composites. Feed it a radial gradient and the text fades in only under the bright part. The output mask mirrors it.

Outputs

image and mask - the composited result, plus the effect mask so you can reuse it downstream. Both pass through cleanly, so you can drop this node mid-chain without breaking anything.

Installing it

cd ComfyUI/custom_nodes
git clone https://github.com/MajoorWaldi/ComfyUI-Majoor-ImageOps

Or search "ComfyUI-Majoor-ImageOps" in ComfyUI Manager, restart, and hard-refresh the browser (Ctrl+F5 / Cmd+Shift+R on macOS). No pip dependencies, no models to fetch - text rendering is Pillow, which ComfyUI already ships. ComfyUI ≥ 0.13.0.

Where people get burned

The per-frame rendering is pure Python, and it loops over the whole batch. On stills that's instant; on a 512-frame render it's CPU time you should budget for - don't expect GPU-speed text burns on long clips. And the font fallback is silent: if your custom font path is wrong, you'll get DejaVu or the default font with no error to tell you. Check the text renders how you expect before committing a long video render to it.

Categoryimage/imageops

Inputs (15)

NameTypeDefaultDescription
bypassBOOLEANfalse
textSTRINGImageOps Text
xFLOAT0.500-2–3
yFLOAT0.500-2–3
font_sizeINT641–512
colorCOLOR#ffffff
opacityFLOAT1.000–1
alignCOMBOcenter3 options: left, center, right
line_spacingINT40–256
stroke_widthINT00–64
stroke_colorCOLOR#000000
invert_maskBOOLEANfalse
imageoptIMAGE,VIDEOImages/Video input.
maskoptMASK
font_pathoptSTRING

Outputs (2)

NameTypeDescription
imageIMAGE
maskMASK