πΌοΈ Embed Image Watermark
Hide a logo inside a photo so nobody can see it β Embed Image Watermark
- image
- watermark_image
- watermarked_image
- info
This is the node that makes the pack worth having: it buries a whole image - your logo, a signature, a QR code - inside another image, invisibly, in the frequency domain. The output looks identical to the input. Anyone who re-posts your work without permission gets to ship your logo around for free, and you can prove it later with the extract node.
Here's the honest framing up front: this is not copy protection, and it won't survive someone aggressively repainting or cropping the image to bits. What it does survive is the stuff that actually happens to images - re-encoding, scaling, mild rotation, cropping, brightness tweaks. That's a lot better than slapping a visible watermark on the corner.
How it works
The pack is a wrapper around the well-known guofei9987/blind_watermark library, and it vendors that library's source inside the repo. The mechanism is DWT-DCT-SVD: the image gets a Haar wavelet transform (DWT), the low-frequency approximation band is chopped into 4Γ4 blocks, each block goes through a discrete cosine transform (DCT), and then singular value decomposition (SVD) modifies the top singular values to encode one bit per block. The blocks are shuffled by a key so the watermark is spread all over the image, and the whole thing runs on all three color channels for redundancy. That redundancy is why it survives cropping - there's enough copies that removing part of the image doesn't remove the message.
Two knobs control the whole game:
- d1 / d2 - how aggressively the singular values get quantized. Higher = more robust, more visible. Defaults are 36/20. The
strengthfloat scales those:d1 = 36 Γ strength,d2 = 20 Γ strength. - passwords -
password_imgkeys the block shuffle;password_wmshuffles the watermark's own bits. They're a key, not a PIN - write them down. Extraction is impossible without the exact pair.
The inputs that matter
- image - the carrier. Bigger is better; a 512Γ512 minimum is the rule of thumb.
- watermark_image - this is where beginners trip. The node converts it to grayscale and then to 1-bit (anything brighter than 128 becomes a 1), so a colorful logo with gradients collapses into a noisy mess. Use a high-contrast black-and-white logo, 64Γ64 or 128Γ128. That's the single biggest quality lever.
- strength - start at 1.0. If extraction comes back garbled, raise it; if you can see the watermark, lower it.
- d1_override / d2_override - optional, default 0 meaning "auto from strength." Only touch these if you know you want to tune robustness vs. visibility by hand.
Outputs are watermarked_image (the carrier with the logo hidden inside) and info, a string reporting the watermark dimensions, passwords, and the d1/d2 it actually used. The info string doesn't matter for the workflow itself, but it's your record of how it was embedded.
Install
cd ComfyUI/custom_nodes
git clone https://github.com/TianDongL/Blind_watermark_Comfyui.git
pip install -r requirements.txt
# restart ComfyUI
Or install "Blind Watermark" via ComfyUI Manager. It's CPU-only, no model downloads - the requirements are just numpy, opencv-python, PyWavelets, qrcode and pyzbar. Note the README's install snippet tells you to cd Comfyui_blind_watermark, which doesn't exist; cd into the folder you just cloned. Also, despite the README listing blind-watermark as a pip package, the pack vendors its own copy - don't pip install blind-watermark, you'd get a second, unused install.
Troubleshooting
- Visible artifacts - lower strength (0.6β0.8) or use a smaller watermark.
- Extraction fails later - the classic cause is re-saving. Save the watermarked image as PNG, and never run it through another JPEG save before extracting. Each re-encode chips away at the signal.
- Watermark image looks like TV static after extraction - it was a low-contrast or color-heavy logo; the 1-bit conversion destroyed it. Redo with a clean B&W logo.
- Password lost? You're done - the whole point of the passwords is that they can't be guessed from the image.
Inputs (8)
| Name | Type | Default | Description |
|---|---|---|---|
| image | IMAGE | β | |
| watermark_image | IMAGE | β | |
| password_img | INT | 11β999999 | β |
| password_wm | INT | 11β999999 | β |
| strength | FLOAT | 1.00.1β3 | β |
| processes | COMBO | auto | 7 options: auto, 1, 2, 4, 8, multiprocessing, +1 |
| d1_overrideopt | INT | 00β200 | Manual d1 parameter (0=auto) |
| d2_overrideopt | INT | 00β100 | Manual d2 parameter (0=auto) |
Outputs (2)
| Name | Type | Description |
|---|---|---|
| watermarked_image | IMAGE | β |
| info | STRING | β |