# 圖片轉 Data URI 圖片 base64 編碼，給 CSS 和 HTML 用

整張圖變成一行文字，直接貼進 CSS 或者 HTML。

> 把 PNG、JPEG、SVG 或 WebP 變成能貼進 CSS 和 HTML 的 data URI。SVG 走百分號編碼而不是 base64，所以還看得懂，也更短。在瀏覽器裡跑，什麼都不上傳。

本頁是一個完全在你的瀏覽器裡執行的互動式工具，地址是 https://abox.tools/zh-TW/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-TW/guides/embed-an-image-in-css/): data URI 的代價在哪裡，base64 為什麼多出三分之一而 gzip 又還不回來，SVG 為什麼絕不該用 base64，以及那個只坑內聯 SVG、還一聲不吭的引號問題。

## 工具箱裡還有

- [SVG 轉圖片](https://abox.tools/zh-TW/svg-to-image/): 說個尺寸。向量圖本來就沒有尺寸可丟。
- [圖片轉 SVG](https://abox.tools/zh-TW/image-to-svg/): 一個形狀，一條輪廓。不該有的東西，點一下就好。
- [身高對比圖](https://abox.tools/zh-TW/compare-heights/): 把身高打進去，把圖帶走。為了畫它，不會往外送任何東西。
- [圖片壓縮](https://abox.tools/zh-TW/compress-image/): 說個大小，剩下的它來算。

## 常見問題

### 我的圖片會傳到什麼地方去嗎？

不會。讀取和編碼都由你自己的瀏覽器在你自己的硬體上完成，用的是瀏覽器早就有的兩個函式。這個工具沒有任何聯網功能，不取東西，也不發東西。頁面的 `Content-Security-Policy` 把它可能聯的地址全列了出來，沒有一個是本站的。

### data URI 是什麼？

一種把整個檔案寫在「本該寫網址的地方」的辦法。原來寫 `url("logo.png")`，瀏覽器就得跑一趟去取；改寫成 `url("data:image/png;base64,iVBORw0...")`，圖片本身就在這串字裡，瀏覽器當場解出來。實際效果是少一次請求，圖片跟著樣式表或者頁面一起到，而不是等它們到了之後再去取。

### 為什麼我的 SVG 沒走 base64？

因為 base64 對它來說是錯的編碼。SVG 本身是文字，而網址本來就能裝文字，只有少數幾個字元需要轉義。把那幾個轉成百分號寫法、別的原樣留著，產生的 URI 通常比同一個檔案的 base64 短五分之一左右，而且在樣式表裡還看得懂，元素名、顏色、`viewBox` 都還在，隨手能改。個別工具鏈非要 `;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-TW/exif-editor/)。

### 為什麼它用的類型跟我的副檔名不一樣？

因為副檔名可能是錯的，位元組不會。一個叫 `logo.png`、其實是按 JPEG 匯出的檔案，常見到每個圖片工具都得應付。而一個類型宣告錯了的 data URI 根本不顯示，沒有備援，也沒有一句值得看的報錯。所以類型是從檔案開頭那幾個位元組讀出來的，這裡涉及的每種格式，開頭都說得毫不含糊。兩邊對不上時，頁面會告訴你。

### 預覽是空白，哪裡出問題了？

多半不是 URI 的問題。HEIC 和 TIFF 都能產生完全合法的 data URI，可除了 Safari 沒有瀏覽器畫得出來，所以你貼到哪裡它就在哪裡缺一塊。先用[圖片壓縮](https://abox.tools/zh-TW/compress-image/)或者[圖片縮放](https://abox.tools/zh-TW/resize-image/)轉成 PNG、JPEG 或 WebP 再說。要是格式本來就很普通，那多半是檔案本身壞了：預覽是拿這個頁面產生的 URI 畫的，畫不出來，就說明這張圖沒能解碼。

### data URI 有長度上限嗎？

在 CSS 裡和 `<img>` 標籤裡，你碰不到什麼上限，現在的瀏覽器在這兩處基本沒有實際限制。瀏覽器真正限制的是把 data URI 打進位址列，稍微長一點的現在多半直接拒絕，那是出於安全考慮，跟這裡的用法沒關係。真正的限制是上面那條：早在技術上出問題之前，你這個頁面已經比老老實實放張圖片更慢了。

### 免費嗎？要註冊嗎？

免費，沒有帳號，不用登入，沒有試用期，也沒有水印。檔案的數量和大小同樣沒有上限，因為沒有哪臺伺服器在為它們掏錢，工作是在你自己的機器上乾的。本站帶廣告，經費就是這麼來的，廣告拿不到關於你圖片的任何資訊。

### 斷網能用嗎？

能。頁面開一次之後斷網，它照常運作。這也是證明「什麼都沒上傳」最省事的辦法。一個把圖片送出去編碼的工具，拔線那一刻就停了。

## 這條隱私承諾怎麼核實

- **你的圖片沒地方可去。** 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` 裡是那項檢查，它算出你即將貼出去的東西裡有多少根本不是畫面。
