Nodes/ComfyUI ARG Toolkit/Invisible Watermark Encode
ComfyUI Node

Invisible Watermark Encode

Bury a message in an image so no human eye can see it

By AzelusLightvale·Created 12 months ago·Updated 4 days ago· 1
Invisible Watermark Encode
  • images
  • IMAGE
messageHello World!
algorithm
types
encoding_format
other_encoding_format

IMWatermarkEncode is the "hidden message in a picture" node - not the visible kind of watermark, but one that's invisible to the eye and survives downsampling, cropping, and JPEG compression to a surprising degree. It's the encode half of the pack's invisible-watermark pair, powered by the invisible-watermark library. Give it an image and a message, get back an image that looks identical but carries your text in its coefficients. This is the node the pack's author was inspired to build after using someone else's watermark node - the README credits ComfyUI_Invisible_Watermark as the reason this whole project started.

How it works

The default algorithm path runs a discrete wavelet transform (DWT) followed by a discrete cosine transform (DCT) on the image, then modulates the transform coefficients to store your bits. The author's own recommendation, echoed in the node description, is dwtDctSvd: the same DWT+DCT pipeline plus singular value decomposition, which makes the watermark noticeably more robust against edits at the cost of a bit more compute. There's also rivaGan, a neural network watermarker that's slow, experimental, and capped at 32 bits of payload - the tooltip says it outright, so treat it as a curiosity.

The types dropdown decides how your message is encoded into bits, and it's where you pick your payload budget:

  • bytes - UTF-8 bytes, ~8 bits per character. Default message "Hello World!" works fine.
  • b16 - hex encoding, ~4 bits per character; denser, slightly more fragile.
  • bits - raw bits, 8 bits per byte; for tiny binary messages.
  • uuid / ipv4 - fixed-size payloads (128 / 32 bits) for embedding a UUID or an IP address, not prose. The tooltip for uuid is blunt: "Do not use to send messages."

encoding_format picks the text encoding (utf-8 by default, with an Other escape hatch via other_encoding_format for exotic codecs).

The output

  • IMAGE - a batch-processed image with the watermark embedded. It runs over every image in the batch, so you can watermark a whole folder in one pass.

Installing it

Part of the ComfyUI ARG Toolkit:

cd ComfyUI/custom_nodes
git clone https://github.com/AzelusLightvale/ComfyUI-ARG-Toolkit

Restart ComfyUI, or install via ComfyUI Manager ("ComfyUI ARG Toolkit"). This is where the pack's install gets heavy: invisible-watermark drags in opencv-python, pywavelets, and numpy. OpenCV and torch are already present in most ComfyUI installs, but on a fresh or minimal setup, the first run can take a while as these land.

Where people get burned

  • The library is experimental and CPU-only. The project's own README says it doesn't support GPU acceleration and isn't production-ready. For a puzzle that's fine; for "this is my DRM" it isn't.
  • Payload limits. Long messages need big images. A watermark has to fit in the image's frequency coefficients, and the author's guidance is that shorter, denser b16 payloads work better than long bytes strings.
  • Decode must match encode. The decoder needs the same algorithm and type, plus the exact payload length. If you encode with bytes and try to decode as b16, you get noise.
  • Recompression. Watermarks degrade with heavy edits. The whole point of dwtDctSvd is surviving more of that abuse.

For the "image that isn't what it appears to be" moment in an ARG, this is the node. Encode a coordinate, a UUID, or a few words, and hand the image off - the secret travels wherever the picture does.

CategoryARG Toolkit/Steganography

Inputs (6)

NameTypeDefaultDescription
imagesIMAGE
messageSTRINGHello World!
algorithmCOMBOIn order of appearance: - dwtDct: Discrete wavelet transform + Discrete cosine transform. Works, but unreliable. - dwtDctSvd (Recommended): Same as above, but includes singular value decomposition. - rivaGan: Uses a 32-bit RivaGAN implementation. Slow, experimental, and limited to 32 bits worth of information.
typesCOMBOIn order of appearance: - bytes: Transforms message to bytes. - b16: Text -> Byte representation -> Hexadecimal -> Byte representation. - bits: 8 bits = 1 byte. Good for transmitting small binary messages. - UUID: Takes a UUID string and embeds that. Do not use to send messages. - IPv4: Takes an IPv4 address and embeds that.
encoding_formatCOMBOThe encoding format available for text, may yield different results when converting.
other_encoding_formatoptSTRINGIf, for some reason, your chosen encoding format is not available in the dropdown, select "Other" in encoding_format and type in your encoding format here. Supports all format written in Python's `encoding` module.

Outputs (1)

NameTypeDescription
IMAGEIMAGE