Hide Text in Image

Hide a message in an image's least-significant bits, with optional AES-256-GCM password encryption, then read it back. Runs entirely in your browser.

🌐 Español

Everything runs in your browser — your image, message and password never leave your device. Hiding text in pixels is concealment, not by itself strong security: it can be detected by analysis tools and is destroyed by re-compression (saving as JPEG, or sending through most social networks and chat apps). For genuine confidentiality, always set a password so the message is encrypted, and share the stego image only as a PNG.

🔒 Private by design: everything runs locally in your browser and never uploaded to any server.

One bit per colour byte, and what that costs the picture

A decoded image is just four numbers per pixel, each from 0 to 255: red, green, blue and alpha. This tool rewrites the last bit of the red, green and blue numbers to carry your message. Flipping that bit shifts a channel by one step out of 256. I ran the embedder over a flat grey buffer and compared every byte afterwards, and the largest change to any single channel was exactly 1.

Alpha is excluded on purpose, and the encoder goes further than skipping it: it forces every pixel’s alpha to 255 as it writes. There is a reason. A PNG encoder is free to throw away the colour values of a fully transparent pixel, and canvas compositing can nudge RGB around under partial transparency, so bits parked in those places can evaporate between save and reload. The component also paints its working canvas white before drawing your picture, which flattens transparency before anything is embedded. Say the consequence plainly, because it is a real trade: hand this tool a logo with a see-through background and the file you get back has a white one.

Reading the capacity line, and what a 1000 by 1000 photo really holds

Choose a file and a line appears under it giving the file name and how much text the image can hold. That figure is not a rule of thumb. It is the width times the height times three, divided by eight, minus the ten-byte header. I put three real sizes through the module rather than doing the arithmetic in my head: a 1000 by 1000 square takes 374,990 bytes, a 1920 by 1080 screenshot takes 777,590, and an 800 by 600 thumbnail takes 179,990.

That capacity line calls those units characters, which is friendly rather than exact. The counter under the message box states the true unit and measures UTF-8 bytes, so plain English costs one byte a letter, an accented Latin letter costs two, most CJK characters cost three, and an emoji costs four. None of that matters for a paragraph of notes. It starts to matter if you try to hide a whole document.

One quirk to know about. The live “too long for this image” warning is only evaluated while the password box is empty, because encryption changes the payload length. Type a password and the counter drops its comparison against the capacity. If the encrypted message then genuinely will not fit, the module refuses rather than truncating, and the page shows you the sentence it threw.

The ten bytes in front of your message

Every embed is prefixed with a fixed ten-byte header, and the whole tool leans on it. Four bytes are an ASCII signature, one byte is a format version, one byte carries flags (bit zero records that the payload is encrypted), and the last four are a big-endian length. Without a length field the extractor would have no idea where your text stopped and would keep converting pixels into nonsense until it ran out of image.

The signature earns its place too. It is what turns “there is nothing here” into an honest sentence instead of a screenful of garbage, and it is why the reveal step can tell you a message is present but locked rather than handing you ciphertext and letting you work it out.

Hiding a message inside a photo

  1. On the Hide a message tab, pick a file with Choose an image. It is read at full resolution, so nothing is downscaled and the capacity stays as high as the picture allows.
  2. Write your text in Type the secret message. As long as the password box is still empty, the byte counter underneath turns red and the action button greys out the moment you overflow the image.
  3. Fill in the Password field if the text is sensitive. Leaving it blank embeds your message as plain readable bytes.
  4. Press Hide message & create PNG, then download the file the page offers. It is named after your original with -hidden.png on the end.
  5. To read it back, switch to Reveal a message, load that file under Choose the stego PNG, retype the password if you set one, and press Reveal hidden message.

The password field is the only part that is really encryption

Concealment and confidentiality are different jobs, and this tool only does the second one when you ask it to. With a password set, your text is handed to the same encryption routine that powers encrypt file and encrypt text: PBKDF2-HMAC-SHA256 at 600,000 iterations to stretch the password into a key, then AES-256-GCM with a fresh sixteen-byte salt and twelve-byte nonce per message. I encrypted a 58-byte sentence through the real function and measured the embedded payload at 115 bytes, so the overhead is a flat 57 bytes regardless of message length. The flags byte records that the payload is encrypted, which is how the reveal step knows to ask for a password instead of handing back ciphertext.

Leave the password blank and there is no encryption at all, only hiding. That is a genuinely weaker thing. If you want signed or public-key messaging with no shared secret to arrange in advance, the PGP tool is the better instrument for the job.

PNG out, and the one thing that erases everything

The output is always a PNG, and that is not a stylistic preference. JPEG saves space by re-quantising blocks of pixels, which scrambles precisely the low-order bits the message occupies. Re-save the file as JPEG and there is nothing left to recover. The same applies to most social networks, most chat apps, and any optimiser that re-encodes what you upload. The reveal tab watches for the obvious version of this mistake and warns you before you press anything if the file you loaded looks like a JPEG.

So the discipline is simple. Do your editing first, on the original picture, using the image tools or a local editor. Blur part of an image if a face needs covering, crop it, adjust it, and only then hide the message. Afterwards, move the exact PNG the tool gave you, as an attachment or on storage that keeps files byte for byte. If you want to see what else is riding along inside that file, the EXIF metadata viewer reads PNG metadata as well as JPEG and will tell you.

See it in action

Screenshot of the Hide Text in Image tool with a two-tab steganography tool - hide a message or reveal one - starting with the numbered steps to choose an image and type the secret text
Hide Text in Image mid-process: a two-tab steganography tool - hide a message or reveal one - starting with the numbered steps to choose an image and type the secret text.
Screenshot of the Hide Text in Image result screen showing the carrier image loaded and ready for the message to be embedded in its pixel data
The finished result: the carrier image loaded and ready for the message to be embedded in its pixel data. The download link is a local blob URL — the file never leaves your device.

Frequently asked questions

How many bits does each pixel actually carry?

Three. One in the red byte, one in the green byte and one in the blue byte. The alpha byte never carries data and is forced to fully opaque as the image is written, so a fussy PNG encoder cannot quietly discard the colour values it sits next to. That works out at three bits per pixel, minus a fixed ten-byte header at the front.

Does the picture I get back look different from the one I put in?

Every colour byte the encoder touches moves by at most one step out of 256, which no display and no eye will show you. Transparency is the part that does change. The working canvas is painted white before your image is drawn onto it, so a source picture with a transparent background comes back with a white one, and the file you download is fully opaque.

What exactly does the optional password do?

It encrypts your text with AES-256-GCM before a single bit is embedded, deriving the key from your password with PBKDF2-HMAC-SHA256 over 600,000 iterations and using a fresh random salt and nonce every time. That is the same code this site's file-encryption tool runs, imported rather than rewritten. The encrypted container costs a fixed 57 extra bytes, so a message near the capacity limit can fit without a password and overflow with one.

Can someone tell that an image contains a hidden message?

Yes, if they think to look. Least-significant-bit embedding leaves a statistical signature that published steganalysis tools are built to spot, and nothing here tries to evade them. Detection is not the same as reading, though. With a password set, all an analyst recovers is ciphertext they still cannot open.

Which errors can the reveal step give me, and what does each one mean?

There are three worth telling apart. A missing four-byte signature reports that no hidden message was found, which almost always means the file was re-compressed somewhere along the way. A signature that is present alongside a length the image cannot hold reports corruption instead. A payload that refuses to decrypt reports a wrong password, so you always know which of the three went wrong.

Should I crop or filter the picture before or after hiding the text?

Before, always. Cropping, resizing, filtering or re-saving the finished file rewrites the very pixel bits the message lives in. Prepare the carrier image first, hide the message as the last step, then leave the downloaded PNG alone.

Related tools