Nodes/ComfyUI-BlindWatermark/Apply Blind Watermark
ComfyUI Node

Apply Blind Watermark

Apply Blind Watermark

By lihaoyun6·Created about a year ago·Updated 12 months ago· 18
Apply Blind Watermark
  • original_image
  • watermark_image
  • image
seed0

You generate something you're proud of, share it, and a week later it's on someone else's feed with their handle on it. This node is the cheap, local answer to that: it bakes a second image - a watermark - invisibly into your output, and you can extract it later to prove the image came from your pipeline. No API, no external service, no key, no GPU. It just works on the CPU, and the watermarked image looks indistinguishable from the original to the human eye.

It's part of ComfyUI-BlindWatermark by lihaoyun6, a port of the well-known fire-keeper/BlindWatermark library. Same author as the hugely popular FlashVSR_Ultra_Fast video upscaler, so this isn't some abandoned weekend script - the pack got a performance-focused update as recently as late 2025.

How it works

The math is older than diffusion and it holds up surprisingly well. The node converts your image to YUV color space, runs a one-level Haar wavelet transform (a "DWT"), chops the result into 6×6 blocks, DCT-transforms each block, and then uses SVD to tweak the largest singular value by a fixed amount. Whether that tweak is "add a bit" or "add more" encodes one pixel of your watermark. The watermark image gets squashed to a 64×64 square, its pixels are shuffled with one seed, and each block's DCT coefficients are shuffled with another seed - both seeds are derived from the seed you provide. To extract the watermark you need that exact seed; without it, the pixels are just noise.

The inputs that matter

Three inputs, that's it:

  • original_image - the image you're protecting.
  • watermark_image - any image; it gets resized to 64×64 and flattened to a square, so aspect ratio is ignored. A logo or a small signature works fine.
  • seed - any integer up to ~1.1 quadrillion. This is the whole game: write it down, because decoding requires the same number.

The output is a single image tensor that you'd wire into a Save Image node. Note the node forces a re-run on every queue (IS_CHANGED is always true) and the result is RGB - any alpha channel gets dropped.

Installing it

The pack has no model files and no heavy dependencies. Install via ComfyUI Manager by searching "ComfyUI-BlindWatermark", or manually:

cd ComfyUI/custom_nodes
git clone https://github.com/lihaoyun6/ComfyUI-BlindWatermark
cd ComfyUI-BlindWatermark
pip install -r requirements.txt

Restart ComfyUI. The requirements are pillow, opencv-python, numpy, pywavelets, and numba - all CPU packages. First run can stall for a few seconds while numba JIT-compiles; that's normal, not a hang.

Where people get burned

  • Forgetting the seed. It's not a password; there's no recovery. Lose it and the watermark is gone forever. Store it next to the image.
  • Too-small images. If the input is small relative to the 64×64 watermark (blocks don't fit), the node raises a RuntimeError - the "Advanced" sibling node lets you shrink the watermark to fix this.
  • Expecting the impossible. DWT-DCT-SVD watermarks survive JPEG compression, mild resizing, and light cropping. They do not survive someone re-running the image through img2img or a denoise pass - re-diffusion scrubs them like it scrubs SynthID. This is provenance insurance against casual theft, not DRM against a determined attacker.
CategoryBlindWatermark/encode

Inputs (3)

NameTypeDefaultDescription
original_imageIMAGE
watermark_imageIMAGE
seedINT00–1125899906842624

Outputs (1)

NameTypeDescription
imageIMAGE