How to calculate how much text an image can hide (3 bits/pixel)
- Step 1Find the carrier's pixel count — Multiply width × height. The encoder uses
img.naturalWidthandimg.naturalHeight, so use the image's true pixel dimensions, not any display or DPI-scaled size. A 1920×1080 image is 2,073,600 pixels. - Step 2Multiply by 3 for the bit budget — Each pixel contributes one bit to each of R, G, B (alpha is skipped in the
i += 4loop, writing only channels 0–2). So the total bit budget ispixels × 3. For 2,073,600 pixels that's 6,220,800 bits. - Step 3Divide by 8 and subtract the terminator — Each character costs 8 bits, and the encoder appends one NUL byte. Maximum characters =
floor(pixels × 3 ÷ 8) − 1. For 6,220,800 bits that's777,600 − 1 = 777,599characters. - Step 4Measure your actual payload — including encryption overhead — Count the characters you intend to embed. If you'll encrypt first with aes-256-encryptor, measure the *ciphertext* length (salt + IV + tag, then base64 ≈ 4/3 expansion), not the plaintext — the ciphertext is what gets embedded.
- Step 5Compare, then pick the carrier — If your payload length is below the carrier's max-character figure, you're safe. If not, choose a larger image. As a rule of thumb, doubling both width and height quadruples capacity (4× the pixels).
- Step 6Encode and confirm — Run the encode in the steganography-encoder. It re-checks
(chars + 1) × 8 ≤ pixels × 3and throws before writing if you're over. If you're round-tripping, keep the payload under the decoder's 100,000-character read cap.
Capacity by carrier size (max Latin-1 characters)
Computed directly from the encoder check (chars + 1) × 8 ≤ pixels × 3. Max characters = floor(pixels × 3 ÷ 8) − 1, with the +1 NUL terminator already subtracted. Each character is one byte.
| Dimensions | Pixels (w × h) | Bit budget (px × 3) | Max characters | Approx. text size |
|---|---|---|---|---|
| 128 × 128 | 16,384 | 49,152 | 6,143 | ~6 KB |
| 256 × 256 | 65,536 | 196,608 | 24,575 | ~24 KB |
| 512 × 512 | 262,144 | 786,432 | 98,303 | ~96 KB |
| 1024 × 1024 | 1,048,576 | 3,145,728 | 393,215 | ~384 KB |
| 1920 × 1080 | 2,073,600 | 6,220,800 | 777,599 | ~759 KB |
| 3840 × 2160 (4K) | 8,294,400 | 24,883,200 | 3,110,399 | ~3 MB |
Capacity needed by payload type
Different payloads consume capacity differently. Encryption and base64 expand the byte count; emoji/CJK aren't safely encodable at all. Plan for the bytes that actually get embedded.
| Payload type | Capacity cost | Planning note |
|---|---|---|
| Plain ASCII / Latin-1 text | 1 byte per character | Direct: length = characters |
| Text + NUL terminator | payload + 1 byte | The encoder always adds one byte |
| AES-GCM ciphertext (base64) | ≈ (plaintext + 44 bytes) × 4/3 | Salt/IV/tag overhead + base64 expansion |
| Base64 of any binary | ≈ original × 4/3 | Embed binaries as base64 to stay ASCII |
| Emoji / CJK | Not safely encodable | Code points > 255 overflow charCodeAt(0) |
Boundary behaviour at the capacity edge
What happens right at and beyond the limit, straight from the encoder logic. The check runs before any pixels are written, so over-capacity attempts produce no file.
| Situation | Outcome |
|---|---|
| Payload = max characters exactly | Encodes successfully (terminator still fits) |
| Payload = max + 1 character | Throws Message too large for this carrier image. Use a larger image. |
| Empty payload (0 characters) | Throws Enter a message to encode. |
| Payload over 100,000 chars | Encodes if carrier allows, but decoder reads only first 100,000 |
| Carrier is animated GIF/WebP | Capacity based on first frame's pixels only |
Cookbook
Worked capacity calculations so you can pick the right carrier on the first try. Every figure uses the real rule: 3 bits per pixel (RGB, alpha skipped), one NUL terminator byte, one byte per Latin-1 character.
Will a 600-word note fit in a 512×512 image?
A 600-word English note is roughly 3,600 characters. Compare against the carrier's capacity before encoding.
Payload: 600 words ~= 3,600 characters
Carrier: 512x512 -> 262,144 px x 3 = 786,432 bits
floor(786,432 / 8) - 1 = 98,303 chars capacity
3,600 <= 98,303 -> fits easily (uses ~3.7% of the LSB budget)Pick the smallest square carrier for a 50 KB document
A 50 KB ASCII document is ~51,200 characters. Find the smallest square image that holds it with the terminator.
Payload: 50 KB ASCII ~= 51,200 characters (+1 NUL = 51,201) 512x512 -> 98,303 cap -> fits (51,201 <= 98,303) 256x256 -> 24,575 cap -> too small Use 512x512 (or larger). 256x256 would throw 'Message too large'.
Account for encryption overhead
Encrypting first makes the embedded payload longer. Size the carrier for the ciphertext, which is ~4/3 of the encrypted byte count and exceeds the plaintext.
Plaintext: 30,000 chars Encrypted: 30,000 + 44 (salt/IV/tag) = 30,044 bytes Base64: 30,044 x 4/3 ~= 40,059 chars <- this is what's embedded 512x512 cap = 98,303 -> fits the 40,059-char ciphertext Don't plan against the 30,000 plaintext figure.
Reverse-solve the dimensions for a known payload
Given a payload, compute the minimum pixel count, then pick dimensions. Useful when you can generate or crop a carrier to size.
Payload: 200,000 chars (+1 NUL = 200,001) Bits needed: 200,001 x 8 = 1,600,008 bits Pixels needed: 1,600,008 / 3 = 533,336 px (round up) A 1024x1024 image = 1,048,576 px -> ample A 768x768 image = 589,824 px -> also fits A 720x720 image = 518,400 px -> too small
Over-capacity fails fast with no file
The encoder validates capacity before touching pixels, so an over-sized payload errors immediately and writes nothing — there's no partial PNG to clean up.
Carrier: icon.png (128x128 -> 6,143 char capacity) Payload: 10,000 characters Result: Error: Message too large for this carrier image. Use a larger image. (no PNG produced) Fix: use a >= 256x256 carrier (24,575 cap) for 10k characters.
Edge cases and what actually happens
Payload exactly equals the max-character figure
Encodes successfullyThe capacity formula already subtracts one byte for the NUL terminator, so a payload exactly at floor(pixels × 3 ÷ 8) − 1 characters fits — the terminator occupies the last available byte. One character more triggers the overflow error.
Payload one character over capacity
RejectedThe encoder checks (chars + 1) × 8 ≤ pixels × 3. Exceeding the max by even one character makes the bit stream longer than the budget, so it throws Message too large for this carrier image. Use a larger image. and writes no file. Use a larger carrier.
Assuming 1 bit per pixel
UnderestimateA common rule of thumb assumes 1 bit per pixel, which underestimates real capacity by 3×. This encoder writes to all three of R, G, B, so the true budget is pixels × 3. Using the 1-bit estimate isn't dangerous — it just makes you pick a needlessly large carrier.
Counting alpha as a usable channel
OverestimateThe encode loop skips index 3 (alpha), writing only R, G, B. Counting 4 bits per pixel overestimates capacity by 33% and can lead you to choose a carrier that throws Message too large. Always plan with 3 channels per pixel, even for transparent PNGs.
Forgetting the NUL terminator in the math
Off-by-one riskThe encoder appends one NUL byte, so the real cost is (chars + 1) × 8 bits. If you size the carrier for exactly chars × 8 bits with no margin, a payload that looks like it fits can overflow by that one byte. The − 1 in the formula prevents this.
Planning capacity from plaintext when encrypting
UnderestimateIf you encrypt first, the embedded payload is the ciphertext, which is longer than the plaintext (salt/IV/tag overhead plus ~4/3 base64 expansion). Sizing the carrier from the plaintext length under-provisions and risks Message too large. Measure the ciphertext.
Carrier is an animated GIF or multi-frame WebP
First frame onlyCanvas drawImage paints one still frame, so capacity is based on that single frame's pixel count — additional frames add nothing. Compute capacity from the frame dimensions, not from a multiplied frame count.
Payload fits the carrier but exceeds 100,000 characters
Decoder-limitedA large carrier can hold far more than 100,000 characters, and the encode will succeed. But the steganography-decoder stops reading at 100,000 characters, so a round-trip returns only the first 100,000. Keep round-trippable payloads under that ceiling or split them.
Using display dimensions instead of natural pixels
Wrong estimateThe encoder uses naturalWidth/naturalHeight (the true pixel grid), not CSS or DPI-scaled display sizes. Computing capacity from a downscaled preview gives the wrong number. Always use the image's actual stored dimensions.
Empty payload
RejectedA zero-length message has nothing to embed, so the encoder throws Enter a message to encode. regardless of how much capacity the carrier has. Capacity planning only matters once there's at least one character to embed.
Frequently asked questions
What's the exact capacity formula?
Maximum characters = floor(pixels × 3 ÷ 8) − 1, where pixels = width × height. The × 3 is the R, G, B least-significant bits (alpha is skipped), the ÷ 8 is because each character is one byte, and the − 1 reserves one byte for the NUL terminator the encoder appends. The encoder enforces it as (chars + 1) × 8 ≤ pixels × 3.
Why 3 bits per pixel and not 1?
The encoder writes one message bit into each of the red, green, and blue channels' least-significant bits, leaving the alpha channel untouched. That's three usable bits per pixel. The widespread "1 bit per pixel" rule of thumb undercounts this carrier by 3×, so it leads you to pick a larger image than you need.
Does the alpha channel add capacity?
No. The encode loop steps i += 4 and writes only channels 0, 1, 2 (R, G, B), never index 3 (alpha). Transparency is preserved but carries no data, so capacity is pixels × 3, not pixels × 4 — even for a fully transparent PNG.
How much does encryption add to the size?
Encrypting with aes-256-encryptor prepends a 16-byte salt and 12-byte IV and appends a 16-byte tag, then base64-encodes everything (≈ 4/3 expansion). So roughly (plaintext + 44 bytes) × 4/3. Always size the carrier for that ciphertext length, which exceeds the plaintext.
Can I hide a 1 MB file in an image?
As text/base64, yes, if the carrier is big enough. 1 MB is ~1,048,576 bytes; as base64 it's ~1,398,101 characters, needing 1,398,102 × 8 ÷ 3 ≈ 3,728,272 pixels. A 1936×1936 (or larger) image covers it. But remember the decoder caps reads at 100,000 characters, so a single round-trip won't recover a payload that large.
What happens if I go over capacity?
The encoder checks capacity before writing any pixels and throws Message too large for this carrier image. Use a larger image. — producing no file. There's no partial output to clean up. Pick a carrier with more pixels: doubling both width and height quadruples capacity.
Do multi-byte / Unicode characters change the math?
They break it. The encoder packs each character with charCodeAt(0) as a single byte, so it only handles code points 0–255 (ASCII + Latin-1). Emoji and CJK exceed 255 and corrupt the stream rather than just costing more bytes. For non-Latin or binary payloads, base64-encode first and plan capacity against the base64 length.
Is there an actual calculator widget in the tool?
No. The Steganography Encoder's only control is the Message to hide textarea. This page is a capacity *reference* — you do the arithmetic (or read it off the table), then encode in the encoder, which validates capacity for you before writing.
Does image content or compression affect capacity?
No. Capacity depends only on the pixel count (width × height), not on what the image depicts or how it was compressed. A noisy photo and a flat gradient of the same dimensions hold exactly the same number of characters. Compression matters for *survival* of the bits, not for capacity.
How does the decoder's 100,000-character cap interact with capacity?
They're independent ceilings. The carrier sets how much you *can* embed; the steganography-decoder only *reads* up to 100,000 characters per pass. If you embed more than 100,000 characters, the encode succeeds but a round-trip returns just the first 100,000. Keep round-trippable payloads under that limit.
Should I size from width×height or the file's byte size?
Always width × height (the pixel count via naturalWidth/naturalHeight). The file's byte size on disk depends on compression and is unrelated to LSB capacity. A 200 KB PNG and a 2 MB PNG of the same dimensions hold identical amounts of text.
What about the file-size tier limits — do they cap capacity?
Indirectly. Capacity is set by pixels, but the carrier file must fit your security tier's size cap (Free 10 MB, Pro 100 MB, Pro-media 500 MB, Developer 2 GB), and the encoder itself is gated to the Developer tier (minTier: "developer"). In practice any raster carrier easily fits under 2 GB, so the tier cap rarely constrains capacity.
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.