图片转 Base64 转换器

将图片转换为 Base64 编码字符串

将图片拖放到此处或点击选择

精确的体积数学:Base64 是压缩也省不回来的 33% 税

Base64 把每 3 个输入字节映射为 4 个输出字符,因此编码后长度精确等于 4 × ceil(n / 3),末尾最多再加 2 个 = 填充。首先就是固定的 +33.3%:30 KB 的 PNG 变成约 40 KB 的文本,750 KB 的照片变成整整 1 MB。字符表是 A–Z、a–z、0–9、+ 和 /(RFC 4648);注意 + 和 / 在 URL 和查询字符串里不安全 — 这正是 base64url 变体把它们换成 - 和 _ 的原因,把标准字符表的字符串直接粘进 URL 参数是经典的数据损坏来源。 这笔税比看上去更狠,因为传输压缩几乎帮不上忙。PNG、JPEG、WebP 的内容本身已经压缩过,字节在统计上接近随机;经过 Base64 之后仍然随机,只是被摊到了 64 个字符的字母表上。作用于外层 HTML 的 gzip 或 brotli 通常只能从编码后的图片里省回 2–5% — 对比一下普通 HTML/CSS/JavaScript 文本常见的 70–80% 压缩率。换句话说,内联进压缩页面的 100 KB 图片,在网络上仍然要花掉大约 128 KB。 唯一可以忽略的开销是前缀:data:image/png;base64, 只增加约 22 个字符。真正要命的是那 33%,而且每一次包含这段标记的页面浏览都要重新支付这笔成本。
const encodedSize = (bytes) => 4 * Math.ceil(bytes / 3);

encodedSize(30 * 1024);   // 30 KB PNG   -> 40 960 chars (+33.3%)
encodedSize(750 * 1024);  // 750 KB JPEG -> ~1 MB of text

// gzip/brotli barely help: compressed image bytes remain
// statistically random after Base64 — only ~2–5% comes back

内联的代价:缓存、懒加载与 Preload Scanner

托管的图片文件独立于 HTML 缓存:改一句文案,回访用户只需重新下载那句话,而不是重新下载 logo。内联的图片则与文档焊死在一起,随每一次 HTML 响应传输,并且每次部署都会失效。跨页面时损失还会叠加 — 在十个模板里重复的 data URL 会被下载十次,而带长 Cache-Control max-age 的托管文件只需获取一次。 懒加载也会悄悄失效。loading="lazy" 推迟的是图片的网络请求,但内联图片根本没有可推迟的请求 — 它的字节就嵌在文档里,会先于其后的所有内容传输,实际上让首屏之下(below-the-fold)的图片变成了阻塞渲染的负载。你还失去了浏览器的 preload scanner(它在解析 HTML 时发现 <img> URL 并并行抓取),以及 CDN 侧的图片优化:格式协商(按 Accept 头返回 AVIF/WebP)、缩放、质量调节,这些都需要一个可寻址的 URL。 内联的历史理由 — 省一个 HTTP 请求 — 随 HTTP/1.1 一起死掉了。在 HTTP/2 和 HTTP/3 上,热连接中的请求是多路复用的,成本只是几十字节的帧开销,而不是一次往返。剩下的只有一个狭窄的甜蜜点:首屏渲染就要用到的、大约 2–5 KB 以下的资源 — 比如一两个 UI 图标,或者在真实照片加载期间占位的模糊 LQIP 占位图。

data: URL 剖析(RFC 2397) — 以及 SVG 为什么应该跳过 Base64

RFC 2397 的语法是 data:[mediatype][;base64],<data>。除了逗号和数据本体,其余部分都可省略,而默认值正是陷阱:省略 media type 时浏览器会按 text/plain;charset=US-ASCII 处理,于是一段完全有效的 Base64 PNG 被当成纯文本解释,渲染成裂图图标。永远把 data:image/png;base64, 写全 — 本工具会自动帮你加上。 SVG 需要特殊对待。SVG 是文本,Base64 对它来说是错误的容器:既要付 33% 的膨胀成本,又摧毁了 gzip 在页面内寻找重复 XML 模式的能力。更好的编码是纯 URL 编码的 data URL:data:image/svg+xml,%3Csvg ... 只需要对会破坏 URL 或 CSS 解析的字符做百分号编码 — <、>、# 和引号;字母和大多数标点都可以原样保留。结果通常在压缩前就比 Base64 版本小 15–30%,压缩后差距更是悬殊,因为 SVG 源码仍是可压缩的文本。# 的规则加倍重要:fill="#f60" 含有裸的 #,不编码的话 URL 会被当作 fragment 截断 — 要编码成 %23。 还有一个字符集陷阱:如果 SVG 里包含非 ASCII 文本(中文标签、箭头、emoji),朴素的 URL 编码 data URL 可能出现乱码。要么把这些字节按 UTF-8 做百分号编码,要么对这一个文件退回 Base64。
/* Raster: Base64 is the only option */
.logo {
  background-image: url("data:image/png;base64,iVBORw0KGgoAAAANS...");
}

/* SVG: URL-encode instead — smaller and gzip-friendly */
.icon {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M12 2 2 22h20z' fill='%23f60'/%3E%3C/svg%3E");
}

/* Missing media type = text/plain assumed = broken image */
/* BAD:  data:;base64,iVBORw0KGgo... */

data: URL 悄悄失效的地方:CSP、Gmail 与导航拦截

Content Security Policy 是第一个埋伏。data: 协议不包含在 'self' 里,所以 img-src 'self' 这样的策略会拦截页面上所有内联图片 — 往往连裂图图标都没有,只剩一片空白,违规记录埋在控制台深处。如果要内联图片,策略里必须显式写 img-src 'self' data:,而安全评审自然会追问原因 — 因为 script-src 或 object-src 里的 data: 是货真价实的 XSS 向量。只对图片开放即可。 邮件是第二个。Gmail 会把 <img src> 里的 data: URI 整个剥掉,其他多数客户端(桌面版 Outlook、Yahoo)行为相同 — 这和人们的预期恰好相反,毕竟"不发外部请求"听起来很适合邮件。HTML 邮件里的图标要么托管在 HTTPS URL 上,要么作为 CID 引用的内联附件。请在真实客户端里测试;ESP 的预览不代表事实。 浏览器还收紧了导航:自 2017 年起(Chrome 60、Firefox 59),指向 data: URL 的顶级导航会被拦截,因为整页 data: 文档曾是流行的钓鱼外壳。在 <img>、CSS、fetch() 里渲染仍然一切正常。至于长度:现代 Chrome 和 Firefox 在 src 属性和样式表里处理几 MB 的 data URL 毫无怨言,但超过 2 MB 左右的 URL 在 devtools 里复制、diff、检查都会变成折磨 — 而老旧的 IE8 把整个 URL 限制在 32 KB,这就是老教程至今还引用那个数字的原因。

内存成本、atob() 的 Unicode 陷阱,以及把决定交给打包器

内联图片要在 RAM 里付三次钱。浏览器同时持有文档里的 Base64 字符串、解码后的文件字节,以及 — 图片一旦显示 — 宽 × 高 × 4 字节的解码位图。最后一项碾压前两项,而且和文件大小完全无关:一张 1000 × 1000 的 PNG,不管文件是 20 KB 还是 2 MB,位图都要占约 4 MB。烤进 JavaScript bundle 的 Base64 是最糟的变种,因为字符串还要经过 JS 解析并常驻堆内存。 如果你用代码而不是本工具来编码,当心那个经典陷阱:atob() 和 btoa() 只支持 Latin-1 字符串。btoa('中文') 会抛出 InvalidCharacterError,而 Stack Overflow 上所有基于 unescape(encodeURIComponent(...)) 的变通方案都已 deprecated。处理文件时,FileReader.readAsDataURL(本页面用的就是它)是正解,根本不会碰到这个问题;处理字节数组时,新近标准化的 Uint8Array.prototype.toBase64() 和 Uint8Array.fromBase64() 终于能正确处理二进制了。 决策规则可以浓缩为三个条件:只有当文件小于约 5 KB、首屏渲染就要用到、且不会跨页面复用时才内联。其余一律保持为托管文件。另外注意,你的打包器已经实现了这条规则:Vite 默认内联小于 4 KB 的 import 资源(build.assetsInlineLimit: 4096),webpack 5 的 asset modules 通过 parser.dataUrlCondition.maxSize 默认 8 KB。如果你在手工内联构建工具决定输出为文件的图片,通常是工具对。
// vite.config.js — Vite already makes the inline/file call
export default {
  build: {
    assetsInlineLimit: 4096 // bytes; imports under 4 KB become data: URLs
  }
};

// webpack 5 equivalent (asset modules)
module.exports = {
  module: {
    rules: [{
      test: /\.png$/i,
      type: 'asset', // data URL under maxSize, separate file above
      parser: { dataUrlCondition: { maxSize: 8 * 1024 } }
    }]
  }
};
最后更新:

关于此工具

图片 Base64 编码器把 PNG/JPEG/GIF/SVG/WebP 转换为可直接嵌入 HTML/CSS/Markdown 的 data: URL。适合邮件模板小图标、单文件 HTML、缓存不重要的 CSS 雪碧图等需要消除额外 HTTP 请求的场景。

使用方法

  1. Drag an image onto the drop zone or click to choose a file from disk.
  2. Wait a moment while the file is read locally — nothing is uploaded to a server.
  3. Preview the image and inspect the generated data: URL or raw Base64 string.
  4. Copy the format you need (full data URL for HTML/CSS, raw Base64 for JSON payloads).
  5. Paste it into an <img src="…">, a CSS background-image: url(…), or a JSON field.

常见用例

  • Inlining small icons in HTML email templates that block external image loading.
  • Embedding a logo in a single-file HTML report (no asset bundle).
  • Storing user-uploaded avatars in JSON when a binary upload pipeline is overkill.
  • Reducing HTTP requests for tiny critical-path images on a landing page.
  • Pasting an image into a Markdown file that needs to be self-contained.
  • Including an SVG favicon directly in <link rel="icon" href="data:…">.

常见问题

Q. How big should an image be before I should NOT inline it?

A. Rule of thumb: under ~5KB for icons. Larger than that you lose caching benefits — the browser cannot cache the image separately and re-downloads it with every page.

Q. Does Base64 increase image size?

A. Yes, by about 33%. SVG is the exception — for SVG you can often avoid Base64 entirely with data:image/svg+xml;utf8,…

Q. Will old browsers render data: URLs?

A. Every modern browser does. Some legacy email clients (older Outlook) strip data URLs in <img>; for email use, test with the actual client.

Q. Is the image uploaded to your server?

A. No. Encoding happens entirely in your browser via FileReader. The image bytes never leave your device.