IE5〜IE7でも、RFC2397(Dataスキーム, DataURI)を使えるようにした!

IE5,IE5.5,IE6,IE7 とおよそ10年に渡り、実装されなかった機能の一つに、Dataスキーム(DataURI) が あります。
uupaa.js version 0.6(近日中にリリース予定)では、DataURI をデコードする機能をエミュレートします。

DataURIって何

ラリーさんがRFC2397で提唱したデータスキームのこと。
ラリーさんってのはこの人。スパタさんにも見えるけどたぶん違う。

平たくいえば、
HTMLファイルに小さなアイコンや 1x1ドット のスペーサーを文字列化して埋め込める。
サーバとネットワークにやさしい仕様。
テキスト + アイコン数個で構成されるページなら、HTMLファイル1個だけで完結することもできるのが魅力。

# 小さな画像をチョコチョコ取得するのって、コスト高
# 負荷軽減の別解としては、小さな画像を1ファイルに敷き詰めて、CSS + clip で切り出して使う方法もあるけどね。

どうやって使うの

<html>
<head><title>DataURI test</title></head>
<body>
<div>
<img id="star" alt="star"
 src="data:image/gif;base64,R0lGODlhDgAOANUAAP%2BZAP8A%2F%2Frx4v3Fb%2F6uNf%2F
      FAPzaqf%2BmD%2F%2F%2F%2F%2F%2FXAP%2B0APzVk%2F60Qvr17f%2BsD%2Fvlw%2F%2Bt
      AP%2FeAPzPgv27VPvivP60Of%2B4D%2F6mIP%2FMAP%2B%2BAP3HeP%2FnAP%2BlCPvr1Pr
      59%2FzVnP%2BsC%2F%2B8C%2F%2BfCv6yMvvfs%2F%2BxFv%2B1Fv64Sfvq0QAAAAAAAAAA
      AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
      AAAAAAAAAACH5BAUUAAEALAAAAAAOAA4AAAZ5wIBwSKF4hsihZ1Q5JpEUk8n49FhHGEzTKv
      RQPpqKIxJxnCQfSgMlChUSG3JBoTiIBB6JZcNPJApzIgNHHgsgcRFZdQtcAR4Tb38FEBONQ
      lhZGBkQDE5dIgkZDg4QEBeeAQIiJRUPFBUHBw1IHQwkVlYGBKi4nrhCQQA7" />
</div>
</body></html>
<html>
<head><title>DataURI test</title></head>
<body>
<div>
<img id="larry" alt="larry"
 src="data:image/gif;base64,R0lGODdhMAAwAPAAAAAAAP///ywAAAAAMAAwAAAC8IyPqcvt3
      wCcDkiLc7C0qwyGHhSWpjQu5yqmCYsapyuvUUlvONmOZtfzgFzByTB10QgxOR0TqBQejhRN
      zOfkVJ+5YiUqrXF5Y5lKh/DeuNcP5yLWGsEbtLiOSpa/TPg7JpJHxyendzWTBfX0cxOnKPj
      gBzi4diinWGdkF8kjdfnycQZXZeYGejmJlZeGl9i2icVqaNVailT6F5iJ90m6mvuTS4OK05
      M0vDk0Q4XUtwvKOzrcd3iq9uisF81M1OIcR7lEewwcLp7tuNNkM3uNna3F2JQFo97Vriy/X
      l4/f1cf5VWzXyym7PHhhx4dbgYKAAA7" />
</div>
</body></html>

のように使います。
# 折りたたんでいるので、つなげて一行にしてください。


本当は、ほかにも使い道があって、

<style>
  list-style-image: url(data:image/gif;base64,R0lG...)
</style>
<script type="text/javascript" src="data:text/javascript;base64,....)

といったこともできるんだけどね。そこまでは実装していません。

今回サポートした機能

以下の条件をクリア場合のみDataURIが使えると思ってください。
結構厳しいことが書いてあります。

  • 特別なこと
    • data:image/gif;base64,R0lGODlhAQABAIAAAAAAAAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw%3D%3D は 1x1の透明なドットのDataURI表現ですが、この文字列を見つけると特別にスペーサーGIFとして認識し、高さと幅に関する制限がなくなります(32x32以上でもOK)。
    • 一度デコードしたGIFファイルのデータは一定期間キャッシュされ、同じ画像であればすばやく処理されます。
    • style属性とwidth,heightでサイズを二重指定すると正しく解釈できません。二重指定しなければ混ぜても大丈夫です。
      • img style="width:100px;height:100px" width="50" height="50" は、width=100px, height=100pxと解釈されるのが正しい仕様ですが、今回の実装では50px,50pxになります。理由はIEがimg.width, img.heightを勝手にバッテンアイコンのサイズに書き換えるのが原因です。
  • 制限
    • data:image/gif;base64 のみ対応。
    • GIF87a, GIF89a の一部に対応
    • GIF89a のインターレースアニメーションGIFが指定されると最初の1枚のみ表示
    • 1ファイル当り約1.3kBまでの画像をサポート(Base64化した状態で約2000byte) → 約3kBまで(Base64化した状態で4kB)
    • 推奨画像サイズは 16x16 〜 32x32
    • 手作りのなんちゃってGIFとか、Trailer(0x3b)の後ろにHackなデータを詰め込んだ偽造GIFは一応大丈夫です。保障しませんが。
  • お勧めの使い方
    • 昔ながらのスペーサーGIF
      • スペーサーGIFとして使用する場合は、環境負荷がほぼゼロです。いくら使っても大丈夫です。
    • ワンポイントのアイコン
      • ページ内に配置する画像は20種類ぐらいが限界と考えてください(このへんはPCの処理能力依存です)。同じ画像を使いまわすのであれば、合計100個ぐらいまで行けると思います。
    • ワンファイル化
      • バグレポート等でHTMLファイルを提出する際に、外部ファイルを全て埋め込んでしまうとか。

DataURI化は?

The data: URI kitchen でできます。

使い方は、

  1. base64をチェック
  2. ファイルをアップロード
  3. Generate をポチっと

上記サイトでやってることは、C言語perl でも10分もあれば出来ると思います。
ファイル読み込んでBase64化して標準出力に出すだけなので。

反省会

  • DataURIがマイナーな存在なのは、IEが実装していないかったから、
    • DataURIは使い方さえ間違えなければ、かなりお勧め。
  • IE8β2でDataURIがサポートされているのに気が付いて作業を開始したので、GIFデコード込みで2日ほどか。
    • MSがDataURIを無視し続けるんだったら、やらなかった。
  • この10年だれもやらなかった理由は、実装してみて初めてわかった。
    • Hex → Base64 → GIFデコード → LZW → Draw(VML) = めんどいなぁもう
      • VMLじゃなくて、テーブルタグでも出来そうだけど、画像の伸縮どうすんねんって問題があるので、キャンバスを使った。

追記

  • 2008-09-05
    • VMLを多用するとIEのライフが簡単にゼロになるので、display="inline-block"を指定したspan要素の中に、絶対位置指定したdiv要素(おいおい)を、ドコドコ追加する方法に切り替えた。
      • spanにdivを追加するのはimg要素の扱われ方(インライン要素なのに高さを持ちパディングが適用される)を再現するため。目的のために手段を問わないというか… 楽ではないのです。
      • table + td だと横幅が必ず2pxになるのでだめだった。