# 图片转 Data URI 图片 base64 编码，给 CSS 和 HTML 用

整张图变成一行文本，直接粘进 CSS 或者 HTML。

> 把 PNG、JPEG、SVG 或 WebP 变成能粘进 CSS 和 HTML 的 data URI。UTF-8 SVG 走百分号编码而不是 base64，所以还看得懂，也更短。在浏览器里跑，什么都不上传。

这是一个浏览器交互工具，地址是 https://abox.tools/zh/image-to-data-uri/。文件在运行该浏览器的设备上处理。主动分享和可选联网功能都在页面上说明。下文是它的文字说明；使用工具请打开该地址。

## 你的图片**在浏览器里处理**，无须上传处理。

编码在你自己的浏览器里、用你自己的硬件完成。它就是对页面手上已有的字节做算术，没有编码器，没有服务器，也没有哪一步联网可以省。这个工具没有任何联网功能，不取东西，也不发东西。就算真有，这个页面的另一头也没有服务器能接住一张图。

- ✗ 不上传
- ✗ 不注册
- ✗ 不重新编码
- ✓ 断网能用
- ✓ 开源

## 图片怎么转成 data URI

1. **选好你的图片。** 拖到下面的方框里，或者点开自己挑。浏览器直接从你的硬盘上读，这期间没有东西发出去。
2. **说清楚这行要粘到哪儿。** 光要 URI，要一条 CSS 规则，要一个自定义属性，要 `<img>` 标签，还是要 Markdown。每一种都替你把 URI 的引号加好了，而引号正是最容易弄错的地方，弄错了偏偏只有 SVG 会出事。
3. **看看代价有多大。** 每个结果都写明它变成了多少个字符、比原文件大出多少，以及这么大的东西内联进去到底合不合算。base64 会多出三分之一，这三分之一值不值一次省下的请求，完全看文件多大，所以页面直接告诉你落在界线的哪一边。
4. **看一眼那些提醒。** 图片要是带着 EXIF、色彩配置文件或者 XMP，页面会点名，并算出你这串结果里有多少字节是它们。扩展名跟实际格式对不上时，按实际格式来，并告诉你一声。浏览器画不出这个结果，它也会直说。
5. **复制，或者下载。** 每个结果一个按钮，另外还有一个把全部结果一次拿走。选自定义属性时，输出外面已经套好一个 `:root` 块，粘到样式表开头就能用。

## 说得更细的版本

[什么时候该把图片塞进 CSS，什么时候不该](https://abox.tools/zh/guides/embed-an-image-in-css/): data URI 的代价在哪儿，base64 为什么多出三分之一而 gzip 又还不回来，SVG 为什么绝不该用 base64，以及那个只坑内联 SVG、还一声不吭的引号问题。

## 工具箱里还有

- [SVG 转图片](https://abox.tools/zh/svg-to-image/): 说个尺寸。矢量图本来就没有尺寸可丢。
- [图片转 SVG](https://abox.tools/zh/image-to-svg/): 一个形状，一条轮廓。不该有的东西，点一下就好。
- [身高对比图](https://abox.tools/zh/compare-heights/): 把身高打进去，把图带走。为了画它，不会往外送任何东西。
- [商家资料预览](https://abox.tools/zh/business-profile-preview/): 把内容打进去，它就变成 Google 会画的那张卡片。为了画它，不会往外送任何东西。

## 常见问题

### 我的图片会传到什么地方去吗？

不会。读取和编码都由你自己的浏览器在你自己的硬件上完成，用的是浏览器早就有的两个函数。这个工具没有任何联网功能，不取东西，也不发东西。页面的 `Content-Security-Policy` 把它可能联的地址全列了出来，没有一个是本站的。

### data URI 是什么？

一种把整个文件写在“本该写网址的地方”的办法。原来写 `url("logo.png")`，浏览器就得跑一趟去取；改写成 `url("data:image/png;base64,iVBORw0...")`，图片本身就在这串字里，浏览器当场解出来。实际效果是少一次请求，图片跟着样式表或者页面一起到，而不是等它们到了之后再去取。

### 为什么我的 SVG 没走 base64？

有效的 UTF-8 SVG 使用可读的百分号编码，通常比 base64 更短。采用其他 XML 编码或包含无效 UTF-8 的 SVG 会自动使用 base64，保留原始字节和编码声明。勾选复选框也会让 UTF-8 SVG 使用 base64。预览仍取决于浏览器能否绘制原始文件。

### base64 会让图片大多少？

大约三分之一。三个字节的文件变成四个字符的 base64，也就是 33%，前面还要再加上 `data:image/png;base64,` 这一截。这是底线，躲不掉，用网址允许的那些字符去表示任意字节，代价就是这么多。也正因如此，页面把字符数摆在文件大小旁边，省得你等样式表都发布了才发现。

### 什么时候内联图片才真的划算？

又小又必须马上出现的时候。每个页面都要加载的样式表里放一个 2 KB 的图标，这是明摆着的赚：少一次往返，CSS 一到图就在。过了大约 10 KB，这笔账就翻过来了。内联进去的图片不再是一个独立文件，没法单独缓存，没法跟别的东西并行下载，而且外面那个文件一改，它就得整个再下一遍。样式表里塞一张 200 KB 的照片，等于给全站每个页面的关键路径都加了 200 KB。每个结果落在界线的哪一边，页面会告诉你。

### gzip 能把 base64 多出来的那部分压回去吗？

没大家想的那么灵。base64 编的要是本来就压过的文件，PNG、JPEG、WebP 都是这种，压出来效果很差，因为里头几乎没有冗余留给压缩器去找了。通常也就找回 base64 多出来那三分之一里的十分之一，绝不是全部。百分号编码的 SVG 正好相反，它还是文本，压缩效果跟原来差不多，这也是不该给 SVG 上 base64 的又一个理由。

### 这一步会动我的图片吗？

不会，而且这一点跟这里多数工具是刻意不同的。没有哪一步把它解码成像素再编回去，从你硬盘上读出来的字节，就是进 URI 的那些字节。JPEG 还是原来那个 JPEG，画质一样，尺寸一样。也正因为如此，结果可以说就是同一个文件，而不是它的一份副本。

### 那 EXIF 和 GPS 也一起进样式表了？

是的，而这正是粘出去之前值得想一想的地方。因为什么都不重新编码，相机写下的东西全都跟着画面走：位置、时间戳、机身序列号。手机照片里这些能占到 30 KB，编成 base64 就是 40 KB 压在你页面的关键路径上，同时还把一个家庭住址提交进了仓库。JPEG、PNG 和 WebP 里到底带了多少元数据，页面会读出来告诉你。想先清干净，用 [EXIF 查看与清除](https://abox.tools/zh/exif-editor/)。

### 为什么它用的类型跟我的扩展名不一样？

因为扩展名可能是错的，字节不会。一个叫 `logo.png`、其实是按 JPEG 导出的文件，常见到每个图片工具都得应付。而一个类型声明错了的 data URI 根本不显示，没有兜底，也没有一句值得看的报错。所以类型是从文件开头那几个字节读出来的，这里涉及的每种格式，开头都说得毫不含糊。两边对不上时，页面会告诉你。

### 预览是空白，哪儿出问题了？

多半不是 URI 的问题。HEIC 和 TIFF 都能生成完全合法的 data URI，可除了 Safari 没有浏览器画得出来，所以你粘到哪儿它就在哪儿缺一块。先用[图片压缩](https://abox.tools/zh/compress-image/)或者[图片缩放](https://abox.tools/zh/resize-image/)转成 PNG、JPEG 或 WebP 再说。要是格式本来就很普通，那多半是文件本身坏了：预览是拿这个页面生成的 URI 画的，画不出来，就说明这张图没能解码。

### data URI 有长度上限吗？

有。浏览器对数据 URL 有有限的大小上限，各实现不同；目标应用或内容策略可能设置更小的上限。CSS 和 `<img>` 可以使用数据 URL，但地址栏导航另有安全限制。请保持内嵌图片较小，并在使用位置测试。[MDN 说明了相关上限和限制](https://developer.mozilla.org/en-US/docs/Web/URI/Reference/Schemes/data)。

### 免费吗？要注册吗？

免费，没有账号，不用登录，没有试用期，也没有水印。文件的数量和大小同样没有上限，因为没有哪台服务器在为它们掏钱，活是在你自己的机器上干的。本站带广告，经费就是这么来的，广告拿不到关于你图片的任何信息。

### 断网能用吗？

能。页面开一次之后断网，它照干不误。这也是证明“什么都没上传”最省事的办法。一个把图片送出去编码的工具，拔线那一刻就停了。

## 这条隐私承诺怎么核实

- **处理在这个浏览器里完成。** 本工具在浏览器里处理输入和结果，处理代码不把它们上传去处理。Content-Security-Policy 限制可用资源和连接目的地，但已允许的主机仍可接收请求。策略不检查载荷，不能单独证明什么都没有发出。请把具体操作的请求与源码核对，或断网完成该本地操作。
- **这里没有任何东西会去联网取数据。** 整个 `src/` 里，一个 `fetch`、一个 `XMLHttpRequest`、一个 `sendBeacon` 都找不到。编码就是 `btoa` 和 `encodeURIComponent`，浏览器从一开始就带着的两个函数，进去是字节，出来是文本，哪儿也不去。
- **预览图本身就是凭据。** 每个结果旁边那张图，是拿这个页面刚生成的 data URI 画出来的，不是拿你的文件画的。它能显示，说明这串 URI 是对的，而且是在你的机器上、没有服务器掺和的情况下对的。要是显示不出来，页面会直说，不会塞给你一个坏的。
- **那条元数据提醒，是站在你这边的。** data URI 是把文件原样抄一遍，所以一张照片的 GPS 定位会跟着一起进你的样式表。这个页面把里面有多少这种东西读出来告诉你，不然你就得等它提交进仓库之后才发现。
- **Google 加载了什么，又拿不到什么。** 广告脚本和统计脚本来自 Google，捐助按钮来自 Buy Me a Coffee。关于你图片的信息，一条都没给它们。读文件、做编码的每一行代码都从本站发出，也都摆在仓库里。
- **断网照样能用。** 断开网络，这个工具跟原来一模一样，因为它本来就没有联网这一步。这是最省事的一条证明。

**你可以自己核对。**上面这些不用你信。这个页面是仓库里的模板和配置生成出来的，构建脚本你能读，也能自己跑一遍，跑出来的结果就提交在 `dist` 分支上。拿实际发给你的内容，跟你自己从源码构建出来的结果对一遍就知道了： https://github.com/A-Box-of-Tools/website

最值得先读的几个文件：`config/site.toml` 里是 Content-Security-Policy，`src/encode.js` 里是那两种编码，以及各自的道理，`src/sniff.js` 里是媒体类型怎么从文件内容读出来、而不是从文件名猜出来，`src/metadata.js` 里是那项检查，它算出你即将粘出去的东西里有多少根本不是画面。
