How to embed an invisible text watermark inside an image
- Step 1Start from the lossless master — Upload your original PNG or BMP master via the dropzone (the picker accepts
.jpg,.jpeg,.png,.gif,.bmp,.webp). Always watermark the lossless master, never a JPEG export — a JPEG source has already had its LSBs disturbed by compression, which weakens the carrier before you begin. - Step 2Write the watermark into 'Message to hide' — The sole control is the
Message to hidetextarea (placeholderHidden text payload…). Type your provenance string — for example© 2026 Jane Doe Photography · licence: AB-1234 · 2026-06-13. There is no separate watermark/strength setting; the text is embedded as-is. - Step 3Keep the watermark in the Latin-1 range — Each character is packed via
charCodeAt(0)as a single byte, so ASCII and Latin-1 (accented letters like é, ü, ñ, and the © symbol at code 169) round-trip perfectly. Avoid emoji or CJK in the watermark — code points above 255 corrupt the bit stream. Transliterate or strip them first. - Step 4Encode the watermark — The encoder reads the pixels, packs
watermark + "\0"into the R/G/B least-significant bits, then callsputImageDataandtoBlob. If the watermark somehow exceeds capacity (rare for short strings) it throwsMessage too large for this carrier image. Use a larger image.before producing any file. - Step 5Download and archive the watermarked PNG — Save the
<name>-stego.png. Treat this as your canonical master from now on — distribute copies of it, and keep the file lossless. Any downstream lossy conversion erases the watermark, so the version you publish should be the PNG itself wherever possible. - Step 6Prove ownership later with the decoder — If ownership is disputed, run the watermarked PNG through steganography-decoder to reveal the embedded text. For a stronger evidentiary trail, also record the file's SHA-256 with multi-hash-fingerprinter when you create it, so you can show the file is byte-for-byte the one you marked.
Watermark survival by downstream operation
LSB watermarks are fragile by nature: they live in the lowest bit of each channel, so any pixel-level change destroys them. This table reflects the real algorithm — bits survive only when the file stays a bit-identical lossless PNG.
| Downstream operation | Watermark survives? | Why |
|---|---|---|
| Copy / move the PNG file | Yes | Bytes are unchanged |
| Re-open and re-save as PNG (lossless) | Usually | Lossless, but re-encoders may differ; verify with the decoder |
| Save / export as JPEG | No | Lossy compression rewrites every LSB |
| CDN or chat app converts to WebP | No | Re-encoding changes pixel values |
| Resize, crop, or rotate | No | Pixels are resampled; the bit grid no longer aligns |
| Brightness / colour adjustment | No | Channel values shift, overwriting the LSBs |
| Screenshot of the image | No | Re-rasterised through the display pipeline |
How much watermark metadata fits (3 bits/pixel)
Capacity is pixels × 3 ÷ 8 characters minus one for the NUL terminator. Watermarks are short, so even a tiny carrier has enormous headroom — keeping the used fraction low, which makes statistical detection harder.
| Carrier size | Pixels | Char capacity | Typical watermark use |
|---|---|---|---|
| 256 × 256 | 65,536 | 24,575 | Copyright line + licence ID (uses <1%) |
| 512 × 512 | 262,144 | 98,303 | Full provenance block + URL |
| 1024 × 1024 | 1,048,576 | 393,215 | Provenance + embedded JSON metadata |
| 1920 × 1080 | 2,073,600 | 777,599 | Enormous headroom — keep payload small for stealth |
Fragile (this tool) vs. robust watermarking
Set expectations correctly: this tool is a fragile LSB watermark with no robustness controls. The columns describe what it is and is not, so you choose the right use case.
| Property | This LSB watermark | Robust (DCT/spread-spectrum) watermark |
|---|---|---|
| Survives re-compression | No | Often yes (not offered here) |
| Survives resize/crop | No | Sometimes (not offered here) |
| Visible artefacts | None (±1/255 per channel) | Possible at high strength |
| Capacity | High (3 bits/pixel) | Lower |
| Best for | Proving ownership of an unmodified PNG you control | Tracking images across re-encodes |
| Configurable strength | No — single fixed mode | Yes (in dedicated tools) |
Cookbook
Practical invisible-watermarking recipes for photographers, designers, and content owners. Every example reflects the real encoder: RGB-LSB embedding, Latin-1 byte packing, NUL terminator, lossless PNG output, and the fragility that comes with it.
Embed a copyright line in a portfolio image
The everyday use case: stamp ownership text into a portfolio PNG with no visible change. The © symbol (code 169) is within Latin-1, so it round-trips fine.
Carrier: portfolio-shot.png (2000x1333 -> ~999,749 char capacity) Message: (c) 2026 Jane Doe Photography | licence AB-1234 | 2026-06-13 Encode -> portfolio-shot-stego.png (visually identical) Decoder check: Output: (c) 2026 Jane Doe Photography | licence AB-1234 | 2026-06-13
Embed structured provenance metadata
Because capacity is large, you can store a small JSON blob of provenance fields instead of a single line. Keep it ASCII/Latin-1 so it round-trips.
Carrier: artwork.png (1024x1024 -> 393,215 char capacity)
Message: {"owner":"Jane Doe","id":"AB-1234","created":"2026-06-13","rights":"CC-BY-NC"}
Encode -> artwork-stego.png
Decoder returns the JSON string; parse it to read the fields.Provenance kit: watermark + hash
A watermark proves what the text says; a hash proves the file hasn't changed since. Combine them for a stronger ownership record.
Step 1 — steganography-encoder: Message: (c) 2026 Jane Doe | AB-1234 Carrier: master.png -> master-stego.png Step 2 — multi-hash-fingerprinter on master-stego.png: SHA-256: 9f2c... (record this in your ledger) Later: re-hash the file; matching SHA-256 proves it is the byte-identical watermarked original.
The watermark vanishes after JPEG export
The most important failure to internalise. Exporting the watermarked PNG to JPEG re-compresses the pixels and erases every LSB. Always publish the PNG, not a JPEG of it.
master-stego.png -> exported as master-stego.jpg Decoder on master-stego.jpg: Output: (no LSB-encoded message detected) The ownership text is gone. Keep and distribute the PNG only.
Resizing also destroys the watermark
Any operation that resamples pixels (resize, crop, rotate) breaks the bit grid the decoder walks. The watermark does not survive a thumbnail or a re-crop.
master-stego.png (1024x1024) -> resized to 512x512 Decoder on the resized file: Output: (no LSB-encoded message detected) Watermark the size you intend to distribute; re-watermark any derivative renditions individually.
Edge cases and what actually happens
Watermarked PNG exported to JPEG
Watermark erasedJPEG is lossy and rewrites the low-order bits during compression, so the watermark is destroyed the moment the PNG is re-saved as JPEG. The encoder outputs lossless PNG specifically to avoid this — keep the file a PNG and publish the PNG itself.
Image resized, cropped, or rotated downstream
Watermark erasedThese operations resample the pixels, so the bit grid the decoder reads no longer aligns and the watermark is lost. There is no resize-resistant mode. Watermark the exact dimensions you plan to distribute, and re-watermark any derivative renditions (thumbnails, social crops) separately.
Colour/brightness adjustment after watermarking
Watermark erasedAny edit that changes channel values — brightness, contrast, curves, a filter — overwrites the least-significant bits where the watermark lives. Apply all edits first, then watermark as the final step before export.
Watermark contains emoji or CJK characters
Corruption riskCharacters are packed with charCodeAt(0) and assumed to fit in 8 bits. Code points above 255 (emoji, CJK, many symbols) overflow a single byte and desynchronise the bit stream, so the decoded watermark is garbage. Keep the watermark in the 0–255 Latin-1 range; the © symbol (169) is fine.
Empty watermark text
RejectedIf the Message to hide field is blank, the processor throws Enter a message to encode. before any Canvas work and produces no file. Enter at least one character of watermark text.
Animated GIF or multi-frame WebP carrier
First frame onlyCanvas drawImage paints a single still frame, so an animated carrier is flattened to its first frame and only that frame carries the watermark. The output is a single static PNG — animation is dropped. Watermark a still image instead.
Watermark is the only proof of ownership
Plan accordinglyBecause the mark is fragile and not cryptographically signed, anyone could re-embed different text into a copy. Treat the watermark as one piece of evidence, not legal proof on its own. Pair it with a recorded SHA-256 from multi-hash-fingerprinter and your own dated records.
Carrier image fails to load
FailedIf the browser cannot decode the upload (corrupt header, unsupported codec, wrong extension), loadImage rejects with Failed to load image and no encode runs. Confirm the file opens in an image viewer and use a standard format from the picker list.
Re-watermarking an already-watermarked PNG
Overwrites the old markThe encoder unconditionally overwrites the LSBs from the start of the pixel array, so encoding a new watermark replaces the previous one — they don't stack. To change a watermark, re-encode the original master with the new text rather than the already-marked file.
Transparent PNG used as carrier
Transparency preservedThe encode loop steps i += 4 and writes only R, G, B — never the alpha channel at index 3. Transparency is preserved exactly and carries no watermark, so a transparent PNG keeps its transparency. Capacity is based on 3 channels per pixel, not 4.
Frequently asked questions
Is the watermark really invisible?
Yes. Each watermarked channel changes by at most 1 out of 255, which is imperceptible on screen and to casual inspection, and the alpha channel is untouched so transparency is preserved exactly. The output is the same dimensions as the original, just re-saved as a lossless PNG.
Will the watermark survive if someone re-saves my image?
Only if it stays a bit-identical lossless PNG. Any re-compression (JPEG, WebP), resize, crop, rotation, or colour edit overwrites the least-significant bits and the watermark is gone. This is a fragile watermark — great for proving ownership of an unmodified PNG you control, not for tracking an image as it's copied and re-encoded across the web.
How do I read the watermark back?
Run the watermarked PNG through steganography-decoder. It walks the same RGB least-significant bits, stops at the NUL terminator, and returns your embedded text (up to 100,000 characters). If the decoder returns "no LSB-encoded message detected", the file has been re-compressed or edited since watermarking.
How much text can I embed as a watermark?
Far more than you'll need. At 3 bits per pixel, capacity is pixels × 3 ÷ 8 characters; a 1024×1024 image holds ~393,215 characters. Watermarks are short, so the used fraction of the LSB budget stays tiny — which is good, because a small payload in a large carrier is harder to detect statistically.
Can I include the © symbol or accented names?
Yes. Characters are packed via charCodeAt(0) as single bytes, so anything in the 0–255 Latin-1 range round-trips — including © (code 169) and accented letters like é, ü, ñ. Avoid emoji and CJK characters, whose code points exceed 255 and corrupt the stream.
Is the watermark encrypted or signed?
No. The text is stored as plaintext bits, and there's no cryptographic signature. Anyone who reads the LSBs can read — or replace — the watermark. If you need the watermark content to be confidential, encrypt it first with aes-256-encryptor and embed the ciphertext; if you need integrity proof, record the file's hash with multi-hash-fingerprinter.
Does this work as a robust, removal-resistant watermark?
No. There is no DCT-domain, spread-spectrum, or error-correcting mode — just the single fixed LSB embedding. It will not survive the re-compression and resizing that robust watermarking schemes are designed to tolerate. Use it for what it is: an invisible, high-capacity, fragile mark on an unmodified original.
Can I prove the file hasn't been altered since I watermarked it?
Yes — pair the watermark with a hash. When you create the watermarked PNG, record its SHA-256 with multi-hash-fingerprinter. Later, re-hashing the file and matching that SHA-256 proves it's byte-for-byte the watermarked original. The watermark says who; the hash says unchanged.
What output format do I get?
Always a lossless PNG named <original>-stego.png, regardless of the carrier you uploaded. The encoder calls canvas.toBlob(..., "image/png") because PNG preserves the LSBs. You can upload a JPEG/BMP/GIF/WebP carrier, but the download — and the version you should distribute — is PNG.
Can I watermark a transparent PNG?
Yes, and the transparency is preserved. The encode loop writes only the R, G, B channels and never touches alpha, so a transparent PNG stays transparent and the watermark lives in the colour channels. Capacity is based on 3 channels per pixel.
Does my image get uploaded to a server?
No. The encode is browser-only — Canvas reads the pixels with getImageData, packs the bits, and toBlob builds the download, all in the page. Your original image and watermark text never leave your machine; there is no server API path.
What if I need to change the watermark later?
Re-encode the original, unmarked master with the new text. The encoder overwrites the LSBs from the start, so watermarks don't stack — encoding new text replaces whatever was there. Keep your lossless master archived separately so you can always re-watermark cleanly.
Privacy first
Every JAD Security operation runs entirely in your browser. Files, passwords, and PGP private keys never leave your device — verified by zero outbound network requests during processing.