Data URI ジェネレーター
画像・フォント・テキストを data: URI に符号化し、また復号します。Base64 とパーセントエンコーディングを実測して比較します。ブラウザー内で動作。
data:image/svg+xml;charset=utf-8,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='%232563eb'%20stroke-width='2'%3E%3Ccircle%20cx='12'%20cy='12'%20r='9'/%3E%3Cpath%20d='M8%2012.5l2.5%202.5%205-6'/%3E%3C/svg%3E
ここではパーセントエンコーディングが短くなります: 255 文字に対し 272 文字、17 文字の節約です。
サイズ
- 元のバイト数
- 174
- URI、Base64
- 272
- URI、パーセントエンコーディング
- 255
URL の中に入ったファイル
data URI は、ファイル全体を URL として書き出したものです。ブラウザーが取りに行くリソースを指し示すのではなく、バイト列そのものを運ぶので、アイコンはそれを使うスタイルシートの中に、小さな画像はそれを表示する HTML の中に置けます。RFC 2397 は 1998 年にこのスキームを定め、以来二十年にわたってあらゆる環境で使えます。
文法は短いものです。スキーム名のあとに省略可能なメディアタイプと省略可能なパラメーターが続き、次に省略可能な base64 フラグ、次にカンマ、そしてデータが来ます。カンマより前がヘッダー、あとがペイロードです。だからブラウザーは最初のカンマで分割し、だからペイロードの中のカンマは無害なのです。
data:[<mediatype>][;base64],<data> data:,hello text/plain;charset=US-ASCII data:text/plain;charset=utf-8,hello the same bytes, spelled out data:image/png;base64,iVBORw0KGgo= binary, Base64 encoded data:image/svg+xml,%3Csvg%20... markup, percent-encoded
空のヘッダーも正当で、その意味は text/plain;charset=US-ASCII です。仕様が与えてくれる唯一の既定値がこれです。このページは、書いた覚えのないメディアタイプを黙って表示するのではなく、既定値を適用したことを報告します。
二つの符号化と、どちらが短いか
RFC はペイロードの書き方を二通り定めています。この選択は好みの問題ではありません。あるファイルについては一方が明確に短くなり、どちらが短いかはファイルの中身に完全に依存します。
Base64 は 3 バイトごとに 64 文字のアルファベットから 4 文字を書き起こします。費用は固定で予測可能です。ちょうど三分の一増え、さらにパディングが付きます。何にでも使えるので、多くの人がまずこれを選びます。
パーセントエンコーディングは、URL で使える文字をそのまま残し、使えない一文字ごとに 3 文字を費やします。ほとんどが素の ASCII であるデータ、たとえば SVG や小さなスタイルシート、JSON の断片では、大半のバイトが手つかずで通るため、結果は Base64 より短くなり、二割から三割短くなることも珍しくありません。逆に PNG やフォントのようにほぼすべてのバイトをエスケープしなければならない場合は、元の 3 倍近くになり、Base64 よりはるかに不利です。
どこまでエスケープするかもまた一つの判断であり、このページは両方の答えを用意しています。
- 厳格な集合は、RFC 3986 の非予約文字、すなわち英数字とハイフン、ピリオド、アンダースコア、チルダ以外のすべてのバイトをエスケープします。結果はどんな文脈でも安全ですが、必要のない記号までエスケープする分だけ長くなります。
- 最小の集合は、data URI の文法が実際に許している文字をそのまま残します。そこにはスラッシュ、コロン、等号、引用符、丸括弧など、マークアップに満ちている文字が含まれます。パーセントエンコーディングが勝つのはここで、属性を単引用符で囲んだ SVG が二重引用符の SVG よりずっと効率よく符号化される理由もこれです。
- 用途がもう一つ規則を加えます。HTML 属性の中では裸のアンパサンドが文字参照を開始してしまうため、img を選ぶとこれもエスケープされます。変わるのはそれだけです。二重引用符、山括弧、バックスラッシュはもともと許容集合の外にあり、どちらの水準でもエスケープされます。
- パーセント記号はどの水準でも常にエスケープされます。エスケープ列を開始する文字なので、文字としてのパーセントは %25 と書かなければ、続く 2 文字が 16 進数として読まれてしまいます。
推測させる代わりに、このページはデータを両方の方式で符号化し、二つの長さとその差を示します。勝ったほうを選ぶか、理由があるなら符号化を手動で指定してください。
33% は圧縮前の数字
data URI をめぐる議論はたいてい、Base64 はファイルサイズを三分の一増やすと繰り返します。算術としては正しく、実務としては誤解を招きます。その数字は回線に乗る前のバイト数を表しており、どのサーバーも送出時にテキストを圧縮するからです。
Base64 は情報を増やしません。同じ情報をより多くの文字に広げているだけで、1 バイトが取りうる 256 通りのうち 64 通りしか使っていません。これはまさに gzip や Brotli が取り除くために存在する冗長性です。PNG や JPEG、WOFF2 フォントのようにすでに圧縮済みのデータでは、圧縮器は中身そのものには手を出せませんが、Base64 の分は元のサイズにきわめて近いところまで詰め直せます。有名な三分の一は大半が消えるのです。
そこでこのページは、主張する代わりに測定します。ブラウザー自身の gzip 実装で三つのものを圧縮します。別ファイルとして配信した場合のデータ、それを Base64 で抱えた文書、そしてパーセントエンコーディングで抱えた文書です。この三つの数字がサイズ論の正直な姿であり、埋め込みの本当の代償はそもそもサイズではないと示すことがよくあります。
本当の代償は別のところにあります。埋め込まれたファイルは単独でキャッシュできないので、それを抱える文書の複製ごとに再ダウンロードされ、二つのページで共有されることもありません。さらに解析を妨げます。スタイルシートは、その真ん中に居座る URI を読み終えるまで解析を終えられません。そもそも埋め込みを魅力的にしていたリクエストごとの代償は、HTTP/2 がほぼ取り除きました。全ページに出る小さなアイコンなら今でも妥当な取引ですが、数十キロバイトを超えると通常は割に合いません。このページが 30 キロバイトから警告を出すのはそのためです。
型はバイト列から決まる
data URI はメディアタイプが正しいときにだけ役に立ちます。間違えれば、ブラウザーは画像の表示を拒み、誤ったパーサーを動かし、あるいは知らない型で提供されたものについてはダウンロードを提案します。
ファイルをドロップすると、ブラウザーは自分なりの型を報告しますが、その報告はファイルの拡張子だけから導かれています。JPEG の名前を .png に変えれば、ブラウザーはそれを PNG と呼びます。このページは代わりに先頭のバイトを読みます。ほとんどの二進形式は署名で始まります。PNG は ASCII に現れえないバイトのあとに PNG の文字が続き、JPEG は固定の 3 バイト、PDF はパーセント記号と PDF の語、WOFF と WOFF2 はそれぞれ 4 文字のタグで始まります。署名と拡張子が食い違えば署名が勝ち、その食い違いは報告されます。
この一覧は意図的に短くしてあります。ブラウザーが判別できるすべてではなく、人が実際に埋め込む形式だけです。どれにも当てはまらず、バイト列が正当なテキストであれば型はテキストとし、マークアップが何で始まるかによって SVG と XML を区別します。まったく当てはまらなければ答えは application/octet-stream で、フィールドは編集可能なままです。誤った推測は、分からないと認めるより悪いからです。
テキストのデータでは文字セットも重要です。仕様の既定は US-ASCII ですが、今日それを意図する人はいません。そこでテキスト系のメディアタイプには charset=utf-8 を付けて提示します。付けなくてもバイト列が壊れるわけではありませんが、読み戻し方は変わります。
逆に読み解く
仕事のもう半分は、こちらのほうがよく起きます。スタイルシートや DOM のダンプ、保存したページの中で data: URI を見つけ、それが何かを知りたい場合です。貼り付ければ、このページが分解します。メディアタイプ、そのパラメーター、使われた符号化、何バイトに復号されるのか、それに対して何文字を費やしているのか、そしてヘッダーの主張とは無関係にそのバイト列が実際は何なのか。画像は描画し、テキストは表示し、それ以外は先頭バイトを 16 進で示します。
復号は厳格です。貼り付けられた URI は信頼できない入力であり、もっともらしい誤答はエラーより悪いからです。カンマの欠落、壊れたメディアタイプ、16 進 2 桁が続かないパーセント記号、Base64 のアルファベット外の文字。いずれも黙って修復せず、問題の位置とともに失敗します。
二つだけは許容します。どのブラウザーも許容しており、折り返されたスタイルシートから写した URI がそうでなければ使えなくなるからです。ペイロード内の空白は取り除き、不足した Base64 のパディングは補います。どちらも報告するので、手元の URI がどこでも通る URI とは少し違うことが分かります。
よく似た一つは、はっきり拒否します。プラスとスラッシュをハイフンとアンダースコアに置き換えた URL セーフな Base64 アルファベットは、JSON Web Token が使うものであって、data URI が受け取るものではありません。黙って受け入れれば、実際に読み込むブラウザーとは違うバイト列に復号することになります。ですから、問題の文字の位置とともに、名指しで拒否します。
どこで動くか
すべてはあなたのブラウザーの中で起こります。選んだファイルはローカルのファイル API で読み込まれ、送信されることはありません。符号化も圧縮の測定も復号もあなたの端末上で行われ、何も保存されず記録されません。ここではそれが多くのページ以上に重要です。人が data URI に変えるファイルは社内の素材であることが多く、調べるために貼り付ける URI は本番のページから来るからです。
よくある質問
- ファイルはどこかにアップロードされますか。
- いいえ。ファイルはブラウザー自身のファイル API でローカルに読み込まれ、あなたの端末で符号化され、どこにも送信されません。復号のために貼り付けた URI についても同じです。
- Base64 とパーセントエンコーディングのどちらを使うべきですか。
- あなたのデータで短いほうです。それはページが測定します。目安としては、SVG、CSS、JSON などのテキストにはパーセントエンコーディング、画像やフォント、すでに圧縮済みのものには Base64 です。差はどちらの方向にも二割から三割になることがよくあります。
- Base64 は本当にファイルを 33% 大きくしますか。
- 圧縮前なら、はい。3 バイトごとに 4 文字です。回線上では、ほとんどそうなりません。Base64 は 1 バイトが取りうる 256 通りのうち 64 通りしか使っておらず、その冗長性こそ gzip が取り除くものなので、圧縮後のサイズは元ファイルの圧縮後サイズに近くなるのが普通です。ページは両方を測定するので、それを目で確かめられます。
- data URI はどれくらい大きくできますか。
- 現代のブラウザーは文書内の URI に厳格な上限を設けていません。ただし古い Internet Explorer は 32 KB に制限していました。サイズは合法性ではなく性能の問題です。埋め込まれたファイルは単独でキャッシュできず、文書の複製ごとに再ダウンロードされます。このページは 1 メガバイトまで符号化し、30 キロバイトを超えると警告します。
- SVG の data URI が CSS で壊れるのはなぜですか。
- ほとんどの場合、エスケープ漏れの文字が原因です。#2563eb のような色に含まれるシャープはフラグメント識別子を開始し、その位置で URI を切ってしまいます。二重引用符は、それが入っている CSS の文字列を終わらせます。SVG の属性は単引用符で囲み、最小のエスケープ集合を使ってください。シャープと二重引用符はエスケープされ、それ以外は短いまま残ります。
- スクリプトや iframe に data URI を使えますか。
- 使えますが、利便性ではなく安全性の問題として扱ってください。data URI はオリジンを継承せず、まさにそのためにブラウザーはトップレベルの遷移をすでに禁じています。script-src や frame-src で data: を許す Content Security Policy は、そのポリシーが守ろうとしていたものの大半を手放します。img-src や font-src で許すのは通常の運用です。
- URL セーフな Base64 が拒否されたのはなぜですか。
- data URI が受け取るのは標準の Base64 だからです。URL セーフなアルファベットはプラスとスラッシュをハイフンとアンダースコアに置き換えますが、これは別の文字であり、別のバイトに復号されます。受け入れてしまえば、実際にその URI を読み込むブラウザーとは違う復号をこのページが行うことになります。
- ブラウザーとこのページでファイルの型が食い違います。どちらが正しいですか。
- このページです。ブラウザーはファイルの拡張子から推測した型を報告するので、名前を変えたファイルでは誤ります。このページはファイル先頭の署名、つまり形式自身が宣言している内容を読みます。上書きする理由があれば、フィールドは編集可能なままです。