LC Watermark π§
LC Watermark π§ β stamp a logo on every frame without leaving the graph
- image
- watermark
- image
LC Watermark composites a logo image onto your output - drag it into place on the preview, set size and opacity, and every frame in the batch gets the mark baked in before save. If you publish images anywhere, this is the node that makes watermarking a step in the pipeline instead of a chore you forget half the time.
The design is refreshingly low-drama: no API, no key, no model - it's a two-image composite with a drag handle. And it has a genuinely clever bypass behavior: feed no watermark image and it passes your image through untouched. That means you can leave the node permanently in your workflow and simply connect a watermark source when you want one. No switching, no bypasser node, no deleting and re-adding.
How it works
Under the hood it's a PIL composite. Your base image plus a watermark image (RGB or RGBA - alpha is respected), and the geometry is all percentage-based so it behaves the same on any canvas size:
- size_percent (1β100, default 20) - watermark width as a percentage of the base width; height follows the watermark's aspect ratio. Resized with Lanczos, so logos stay crisp.
- opacity (0β1, default 0.85) - how see-through the mark is. At 1.0 it's fully opaque.
- x_percent / y_percent (0β100, defaults 90/90) - the center of the watermark, bottom-right corner by default. Drag on the preview to set these; they update live after the first run.
- margin_percent (default 0.5) - edge padding, a small inset so the mark doesn't touch the border.
The watermark is positioned by its center within the usable area (image minus margins), then clamped so it can never fall off the edge. One image in, one image out - plus the optional watermark input socket that triggers the bypass when unconnected.
Where people get burned
First run can confuse: the tooltips say size/opacity/position are "live on node after first run." The drag-to-place interaction needs a run under its belt, so queue once, then drag. Not a bug, just the node's order of operations.
Second, and more practically: your watermark should have a transparent background or a matching background color. If you feed it a white-background PNG, you get a white rectangle pasted over your image at whatever opacity you set. Make the logo a transparent PNG and 90% of watermarking pain disappears. (If you need to knock out a background first, that's a background-removal pass upstream - this node will composite whatever you hand it, faithfully.)
Also worth noting: watermarking does nothing to stop someone cropping your logo off, and it isn't a substitute for metadata sidecars or content credentials. It's a visible deterrent, not DRM.
Install
Part of lonecatone23's ComfyUI_LC123_nodes pack, which ships ~89 utility and image nodes with no extra pip packages - ComfyUI's torch/numpy environment covers it. Install:
- ComfyUI Manager - search "LC123" or "ComfyUI_LC123_nodes", install, restart.
- Manual -
cd ComfyUI/custom_nodes && git clone https://github.com/lonecatone23/ComfyUI_LC123_nodes, restart.
The honest verdict
For a node whose entire job is "put a small image on a big image," it's well-executed: RGBA-aware, percentage-scaled, drag-placed, and the no-watermark-input bypass is the kind of thoughtful touch that means you'll never accidentally render an unmarked batch again. It won't stop a determined thief, but it will stop the lazy one - and it does it without breaking your flow.
Inputs (7)
| Name | Type | Default | Description |
|---|---|---|---|
| image | IMAGE | β | |
| size_percent | FLOAT | 20.01β100 | Watermark width as % of base width. Live on node after first run. |
| opacity | FLOAT | 0.850β1 | Opacity 0β1. Live on node after first run. |
| x_percent | FLOAT | 90.00β100 | Horizontal center %. Drag on preview to set. |
| y_percent | FLOAT | 90.00β100 | Vertical center %. Drag on preview to set. |
| margin_percent | FLOAT | 0.50β10 | Edge padding as % of image (small, similar to Text Overlay ~6px). |
| watermarkopt | IMAGE | Watermark (RGB/RGBA). Missing = bypass (pass-through). |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| image | IMAGE | β |