Image to Base64: encoding, decoding and data URIs

To convert an image to Base64, encode its raw bytes and add a prefix: base64 -w0 image.png on Linux, base64 -i image.png on macOS, or the PowerShell one-liner below on Windows. Put data:image/png;base64, in front of the output and you have a data URI: the file's bytes carried as plain text, ready to paste into an <img> tag, a stylesheet or a JSON payload. This page shows working examples, the honest pros and cons, and how to decode the string back into the original file.

What a data URI is made of

Every data URI has three parts. The data: scheme marks it as inline content. Then the MIME type and the encoding marker, image/png;base64. Then, after the comma, the file itself: every 3 bytes of the original rendered as 4 characters from the Base64 alphabet (letters, digits, + and /, padded with =).

Here is a complete, working example. The image is a real 8-by-8 pixel PNG, 74 bytes as a file and 100 characters once encoded:

<img width="8" height="8" alt="a small orange square"
  src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAIAAABLbSncAAAAEUlEQVR4nGP4EKWBFTEMLQkAVuRcge/othAAAAAASUVORK5CYII=">

The same trick works in CSS:

.badge {
  background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAIAAABLbSncAAAAEUlEQVR4nGP4EKWBFTEMLQkAVuRcge/othAAAAAASUVORK5CYII=);
}

No file request, no second round trip: the browser decodes the string back into bytes the moment it builds the page.

When inlining an image helps

Email is the exception: many clients strip data URIs for security reasons, so attach the image instead of embedding it.

When it hurts

Encode an image from the command line

A browser paste box holds text, not raw file bytes, so image files go through one line of command. Each of these prints the Base64 string to the terminal:

# Linux (GNU coreutils): -w0 keeps the output on one line,
# the default wraps every 76 characters
base64 -w0 image.png

# macOS (BSD base64): no -w flag, and it does not wrap by default
base64 -i image.png

# Windows PowerShell
[Convert]::ToBase64String([IO.File]::ReadAllBytes("image.png"))

To produce the full data URI in one step on Linux or macOS:

echo "data:image/png;base64,$(base64 -w0 image.png)" > image.b64

Decoding back is where Linux and macOS disagree, and it bites people who copy commands between them:

TaskLinux (GNU)macOS (BSD)
encode a filebase64 -w0 image.pngbase64 -i image.png
decode to bytesbase64 -d image.b64base64 -D image.b64

On macOS the decode flag is a capital -D. Lowercase -d is a different flag there, so a Linux command pasted onto a Mac does not decode, and on many versions it quietly does something else instead. Check the output file before you trust it.

To prove a round trip worked, decode into a new file and compare bytes:

base64 -w0 image.png | base64 -d > copy.png
cmp image.png copy.png   # no output means byte-identical

Base64 of text strings (not files) is a different job, and our Base64 tool does it live in your browser: nothing is uploaded, nothing stored.

Decode Base64 back into an image

The command-line decode from the table above rebuilds the exact original file, byte for byte. Redirect into a new filename; decoding in place over the source file destroys it, because the shell truncates the target before the decoder reads it.

For a quick visual check without the terminal, drop the data URI into a scratch HTML file and open it:

<!-- check.html -->
<img src="data:image/png;base64,PASTE-YOUR-STRING-HERE" alt="check">

One caution with strings you did not create. Base64 is a transport format, not a safety check, so treat decoded bytes from strangers the way you treat any downloaded file. Keep untrusted images inside <img> tags, where they render but cannot execute anything. SVG is the sharp edge: opened as a document rather than embedded, an SVG can carry scripts, which is exactly why current browsers refuse to navigate directly to a data: URL. Decode with your terminal, view inside an img, and never run what you have not inspected.

The limits worth knowing

Frequently Asked Questions

How do I convert an image to Base64?

Run one command on the file: base64 -w0 image.png on Linux, base64 -i image.png on macOS, or [Convert]::ToBase64String([IO.File]::ReadAllBytes("image.png")) in Windows PowerShell. Prefix the output with data:image/png;base64, and the whole string is a data URI you can paste into an img tag, a CSS url() or a JSON field.

Why is Base64 bigger than the original file?

Base64 encodes every 3 bytes of input as 4 characters, and 4 divided by 3 is about 1.33. A 100 KB image becomes roughly 133 KB of Base64, plus a couple dozen characters for the data: prefix. The size premium is the price of carrying binary data through formats that are built for text.

Can I put Base64 images in CSS?

Yes: a background-image with url(data:image/png;base64,...) works in every current browser. Keep it to small icons. A large image inside a stylesheet makes the stylesheet heavier and delays first paint, because browsers download all of the CSS before rendering anything it describes, and the image also loses its own cache entry. IE8 capped CSS data URIs at 32 KB, but that limit is history.