Apply Blind Watermark (Advanced)
The Three Knobs That Decide Whether Your Watermark Survives or Shows
- original_image
- watermark_image
- image
The plain Apply Blind Watermark node hides a watermark with sensible defaults. This one is the same operation with the training wheels off - and the three extra dials it exposes are the difference between a watermark that's invisible but fragile and one that's a bit visible but tough. You trade robustness against artifacts, always. There's no free lunch here, and the author says so in the tooltip: larger strength is more robust but more artifacts, larger block_size is more invisible but may not fit, larger robustness is more robust but may not fit.
It's in ComfyUI-BlindWatermark, lihaoyun6's CPU-only port of the fire-keeper/BlindWatermark library. Same author as FlashVSR_Ultra_Fast, actively maintained into late 2025, no models, no GPU required.
What the knobs actually change
All three map directly to parameters in the underlying DWT-DCT-SVD algorithm:
- strength (10–99, default 30) - the SVD modulation size. Each watermark bit is encoded by nudging the largest singular value of a DCT block toward one of two target values,
strengthapart. Higher = the bit is pushed further apart = survives more JPEG compression and noise, but the nudges add visible texture. This is the one you crank when watermarked images keep getting mangled. - block_size (2/4/6/8, default 6) - the size of each block you embed one watermark bit into. Bigger blocks spread the change over more coefficients, which is why larger = more invisible. But a bigger block means fewer blocks fit in the image, and if there aren't enough blocks for the watermark's pixels, the node dies with
Unable to embed watermark! Try reducing "watermark_size" or "block_size" or "robustness"! - robustness (1/2/3, default 1) - the number of Haar wavelet decomposition levels. Each extra level halves the resolution you embed into, making the mark survive harsher edits. The catch is the same capacity squeeze: deep decomposition needs a bigger source image.
- watermark_size (default 64, step 2) - the square size your watermark gets squashed to. Smaller = needs fewer blocks = fits small images. The basic node is locked to 64; this is how you fit a watermark into a 512×512 thumbnail.
Inputs are original_image, watermark_image, and seed - the seed is shared with the basic node and is still the thing you must never lose, since decoding derives the pixel-shuffle keys from it. Output is one image tensor for your Save Image node.
The gotcha that bites everyone
Whatever non-default values you set here must be repeated at decode time. The simple Decode Blind Watermark node silently uses strength 30 / block 6 / size 64 / robustness 1. If you encode with custom values and then decode with the basic node, you'll get back a watermark that's faint, wrong, or flat-out garbage - and no error to tell you why. Encode with this node, decode with Decode Blind Watermark (Advanced) using identical settings. The simplest workflow that stays consistent: encode and decode both at defaults, and you can use the basic pair.
Installing
Same as the rest of the pack: ComfyUI Manager → search "ComfyUI-BlindWatermark", or git clone https://github.com/lihaoyun6/ComfyUI-BlindWatermark into custom_nodes/, then pip install -r requirements.txt and restart. That's pillow, opencv-python, numpy, pywavelets, numba - nothing GPU-bound. Give the first run a few seconds for numba's JIT compile before you think it hung.
The takeaway: start with this node only when the default watermark fails to survive your actual use case (compression, cropping, resizing). Otherwise the basic node's defaults are genuinely fine - and matching every knob between encode and decode is a chore you don't want to debug at 1am.
Inputs (7)
| Name | Type | Default | Description |
|---|---|---|---|
| original_image | IMAGE | — | |
| watermark_image | IMAGE | — | |
| seed | INT | 00–1125899906842624 | — |
| watermark_size | INT | 64 | — |
| strength | INT | 3010–99 | — |
| block_size | COMBO | 6 | 4 options: 2, 4, 6, 8 |
| robustness | COMBO | 1 | 3 options: 1, 2, 3 |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| image | IMAGE | — |