IMAGE BASE64 TOOL● Browser-local

IMAGE UTILITY / 04

Base64 encode image

Whether to inline an image, not how to encode one. The measurement runs in your browser on your own file. Nothing is uploaded.

Inline an image only when all three of these are true. If any one fails, serve it as a file instead.

  1. The file is small enough that the bytes it adds are noise next to the document it rides in — for a 30 KB document that lands between 255 and 367 bytes depending on the format, not 10 KB.
  2. Exactly one document uses it. The moment a second page inlines the same file you have paid for it twice, and the separate copy would have been cached after the first fetch.
  3. It is not text or vector. Measured, an inlined SVG is the worst case of every format I tested: +50% under gzip and +67% under Brotli.

The familiar “+33%” is real, and it is not what you end up paying. Gzip gives back most of it — 86.6% of the overhead for a PNG, and more than all of it for a JPEG. That is the part the usual advice leaves out. Need the string itself? The converter on the home page does that; this page only answers whether you should.

01 / Your file

The measurement is gzip level 9, run on this device just now.
Files over 8 MB are skipped rather than made to hang the tab.

02 / What inlining would cost

    Where the 10 KB number comes from, and what it skips

    The advice you will find repeated is that images under about 10 KB are fine to inline. No page I have read shows the arithmetic behind that figure, and none of them splits it by format or re-runs it after compression. Both omissions change the answer, so here is the derivation with every input written down.

    Input 1 — the raw inflation is exact, not approximate

    Base64 carries 6 bits per character, so three bytes become four characters. The length is therefore exactly 4 × ⌈bytes ÷ 3⌉, with up to two = for padding. Across the nine files I measured, the inflation landed between +33.33% and +34.13% — the top of that range is the 167-byte SVG, where the two padding characters matter most. Treat +33.33% as the floor and add the padding.

    Input 2 — compression gives most of it back, and the amount depends on the format

    This is the input the usual advice never mentions. A server gzips the document it sends, Base64 text included, so what matters is the compressed size of the Base64 text, not its length. I gzipped both the file and its Base64 text at level 9, and Brotli at quality 11, for each sample:

    What was inlinedFile bytesBase64 charsRaw +%File gzippedBase64 gzippedInlined ÷ fileBrotli ÷ fileOverhead recovered
    PNG, 640 × 3605,8797,840+33.36%4,6524,9141.056×1.055×86.6%
    JPEG, 640 × 36015,08420,112+33.33%13,26213,1470.991×0.995×102.3%
    WebP, 640 × 3609,25412,340+33.35%8,9488,9330.998×1.003×100.5%
    PNG icon, 32 × 32615820+33.33%6386551.027×1.031×91.7%
    PNG, 200 × 200 flat colour1,6432,192+33.41%1,5461,6001.035×1.056×90.2%
    PNG, 200 × 200 with alpha4,9516,604+33.39%4,9414,9981.012×1.020×96.6%
    Raw RGBA, 200 × 200160,000213,336+33.34%1964712.403×2.556×99.5%
    BMP, 200 × 200 flat colour120,054160,072+33.33%1912371.241×0.934×99.9%
    SVG, 200 × 200 (text)167224+34.13%1342011.500×1.667×−17.5%

    Read the last three columns. For an already-compressed raster — JPEG, WebP, PNG — gzip recovers essentially the whole third, so inlining costs between 0.99× and 1.06× of what the file would have cost gzipped. For the SVG it goes the other way: the overhead grew by 17.5% under gzip and 67% under Brotli, because Base64 turns compressible text into something that looks closer to noise. A flat 33% is the wrong number for every one of these nine files.

    Two rows look strange and are worth the second look. The 200 × 200 raw RGBA buffer is 160,000 bytes that gzip collapses to 196 — and its Base64 to 471, a ratio of 2.403×. Inlining a compressible binary costs you a multiple of the file, not a third more. And the 32 × 32 icon is 615 bytes that gzip makes larger (638), because gzip's own header outweighs any gain on something that small. Small compressed files do not benefit from gzip at all.

    Input 3 — the same file in more than one document

    An inlined asset travels inside every document that contains it. A file served separately is fetched once and then cached. So with the asset in K documents, inlining costs K × gzipped(Base64) while the separate file costs gzipped(file) once. Inlining wins on bytes only while K is below gzipped(file) ÷ gzipped(Base64). Across my nine samples that break-even came out at 0.947, 1.009, 1.002, 0.974, 0.966, 0.988 and 0.667 — every one of them at or under 1.01. At two documents, inlining has already lost on bytes in every case I measured.

    The threshold, worked out

    Write G for the gzipped size of the document you are adding to, and r for the measured ratio of gzipped-Base64 to file bytes from the table above. Pick a budget — the share of your document you are willing to give away. Then:

    largest file worth inlining = budget × G ÷ r

    I use a 1% budget. It is a choice, and I am stating it as one rather than presenting it as a law. Here is what it produces, with r taken from the measurements:

    Formatr (gzipped Base64 ÷ file bytes)Largest file for a 30 KB documentLargest file for a 100 KB document
    PNG, photo-like0.836367 B1,225 B
    JPEG0.872352 B1,174 B
    WebP0.965318 B1,061 B
    PNG, flat colour0.974315 B1,051 B
    PNG, with alpha1.009304 B1,015 B
    PNG, small icon1.065288 B961 B
    SVG, text1.204255 B850 B

    So for a 30 KB document the honest ceiling is 255 to 367 bytes, and it is not one number — the format moves it by 44%. Run the same sum for the quoted 10 KB and see what it means: inlining a 10,240-byte PNG into a 30 KB document adds 10,240 × 0.836 ≈ 8,561 bytes, a 27.9% increase, not a rounding error. The figure people repeat is not a bytes threshold. It is a threshold from a different argument, and this page is deliberately not making that argument — see below.

    What this page does not answer

    There is a second, separate case for inlining: it removes a request, and requests have their own cost. Whether that cost still exists once connections are multiplexed is a different question with different inputs, and it is not measured here. Everything on this page is the bytes side only, and on the bytes side the answer above is the whole answer. If your reason for inlining is the request, say so — the arithmetic here will not support it either way.

    Two related questions also live elsewhere. If you want to know whether your string is damaged, that is Base64 to image. If you want to know which container to save it in — PNG or JPEG, and what each costs — that is Base64 to PNG. And if you just want the encoded string, the converter is on the home page.

    How these numbers were produced

    Nine samples, generated on this machine and written to disk: a 640 × 360 PNG (5,879 bytes), the same picture as JPEG at quality 92 (15,084) and as WebP at quality 92 (9,254), a 32 × 32 PNG icon (615), a 200 × 200 flat-colour PNG (1,643), a 200 × 200 PNG with alpha (4,951), a 200 × 200 raw RGBA buffer (160,000), a 200 × 200 24-bit BMP (120,054), and a 200 × 200 SVG (167 bytes of text). Each was compressed twice — the file itself, and its Base64 text — with gzip at level 9 and Brotli at quality 11. The ratio column is gzipped-Base64 ÷ gzipped-file; r is gzipped-Base64 ÷ file bytes. The in-browser calculator uses the same gzip level, and I confirmed it returns identical byte counts to the offline runs on the 5,879-byte PNG: 4,652 and 4,914. Brotli is not available through the browser's compression stream, so those figures come from the offline runs only.