Image to Base64 — A Data URL, an img Tag, or the Raw String, With the Real Size Cost
Pick a picture from this device and get back exactly the form you need: a data URL, the raw base64 string, an image tag, a CSS background rule, or a JSON value. The type comes from the file's own magic bytes rather than its extension, so a .jpg that is really a PNG says so. Every output is measured - bytes in, characters out, the size change, and a table of which destinations that string can actually be pasted into. Paste base64 back in to decode it, check the padding, see the picture and save it as a file. Nothing you pick leaves this device.
Where a string this size can actually go
| Destination | What limits it | This payload |
|---|
Base64 back into a picture
| Checked | Result |
|---|
Sixty-four characters, and the size price
Why a sixty-four character alphabet exists at all
Plenty of channels insist on carrying text and get nervous about the other 192 byte values. MIME mail bodies, config files, URLs, JSON inside a log line, a cookie value - each of them in its own way says “give me characters I can print”. Base64 answers by spending six bits per character: A-Z, a-z, 0-9, then + and /, which is sixty-four symbols and exactly sixty-four, because sixty-four is 2^6.
Three bytes are 24 bits, and four characters hold 24 bits, so the packing is even and nothing is lost. When the file ends on one or two spare bytes the last group comes up short, and the = signs record how short. That is the entire design, and it explains the two facts printed beside the output: the string is always a multiple of four characters long, and it is always a third larger than the file.
The third is the price, and it is not always worth paying
A 12,000 byte icon becomes 16,000 characters. The table under the output box works that number against the limits that actually bite, and it is deliberately split between what is specified and what is merely what the software ships with: a cookie’s 4,096 bytes is a browser behaviour you can rely on, MySQL’s 65,535 for TEXT is a documented ceiling, nginx’s 1 MB body cap is a default someone can raise, and localStorage has no size in any specification at all - the engines just happen to converge near 5 MB. Anything that reports “fits” is only true for the file you picked a minute ago.
Then there is the cost no byte counter shows. A data URL inside your HTML is part of your HTML: it cannot be cached on its own, so every page view re-sends it; it cannot load in parallel with the rest of the document; it makes the document bigger to parse; and if your site has a CSP, it probably says img-src without data:, and the picture simply does not appear. For a sprite of ten 1 KB icons it is a good trade - one request instead of ten. For a 2 MB hero photo it is a bad one, and the numbers above will show you the shape of that mistake before you commit it.
Two alphabets, and where each one is legal
+ and / are not URL-safe: + means a space in a query string, and / means a path separator. The URL-safe variant swaps them for - and _ and is what JWTs, file names and database keys use. It is not what a browser reads in a data: URL, which is why the standard alphabet is what the three forms that go into a document get, and the swapped one only arrives when you asked for a string you will transport yourself.
Why the first bytes beat the file name
A .jpg that is really a PNG has a valid name and an invalid header. The header is what gets read - PNG’s ‰PNG, JPEG’s FFD8, RIFF….WEBP, and so on - and both the claim and the evidence are reported when they disagree, because the type written into the prefix is what your browser will believe. Screenshots renamed by hand, images that came out of a converter that kept the old extension, and files that arrived from a web page with the wrong Content-Type all look like this.
What the decoder refuses to guess
Paste a string back in and it gets a full check before anything is unpacked: the length modulo four, the number of padding signs and whether any of them sit in the middle, characters from neither alphabet with their position, and the leftover bits in the final group - the ones base64 cannot represent, which a canonical string always leaves zero. If those bits are not zero it says so, because the string you pasted was mangled somewhere upstream, and re-encoding it will not give you the same characters back.
It will not silently accept a data: URL that is not marked base64, since that one holds percent-encoded text and un-escaping it is a different operation. And it never repairs a truncated string: a picture that stops halfway decodes into a file your browser will refuse to draw, and the honest answer is that the copy lost its tail.
Questions
Q: Does my picture get uploaded? No. The bytes are read into this tab by the browser’s own file reader and walked by loops in its script. The picture is not posted anywhere, no server sees it, and the string you copy was built from bytes that never left this device.
Q: Why is the output longer than the file? Because every three bytes leave as four characters. Base64 is not compression; it is a translation into an alphabet that nervous channels will carry.
Q: Can I encode a picture bigger than the 8 MB cap? The cap is what stops it, not the format - because a 40 MB string in a textarea is not something you can paste anywhere useful. Point at a real encoder, or reference the file by path.