Nodes/ComfyUI-BlindWatermark/Apply Blind Watermark (Advanced)
ComfyUI Node

Apply Blind Watermark (Advanced)

The Three Knobs That Decide Whether Your Watermark Survives or Shows

By lihaoyun6·Created about a year ago·Updated 12 months ago· 18
Apply Blind Watermark (Advanced)
  • original_image
  • watermark_image
  • image
seed0
watermark_size64
strength30
block_size6
robustness1

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, strength apart. 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.

CategoryBlindWatermark/encode

Inputs (7)

NameTypeDefaultDescription
original_imageIMAGE
watermark_imageIMAGE
seedINT00–1125899906842624
watermark_sizeINT64
strengthINT3010–99
block_sizeCOMBO64 options: 2, 4, 6, 8
robustnessCOMBO13 options: 1, 2, 3

Outputs (1)

NameTypeDescription
imageIMAGE