Base64 を ICO に変換する方法
- Base64、
data:image/x-icon;base64,...形式の URI、または<link rel="icon" href="data:...">タグ全体を貼り付けます。 - ステータス行の 検出 に ICO と表示されていることを確認し、プレビューを見ます。
- ファイルをダウンロード を押します。名前の初期値は
decoded.icoです。Web サイトに置くならfaviconに変更してください。
MIME タイプ 欄には、ほとんどのサーバーや data URI がアイコンに使う image/x-icon が表示されます。
ICO ファイルには複数の画像が入っている
PNG や JPEG と違い、ICO ファイルは小さなコンテナです。一般的な favicon.ico には 16×16、32×32、48×48 の画像が入っていて、Windows のアプリケーションアイコンには 256×256 も加わることがよくあります。Windows はタスクバー、デスクトップのショートカット、エクスプローラーのそれぞれに最適なサイズを選び、ブラウザはタブ用に 1 つを選びます。
ファイルは 6 バイトのヘッダーで始まり、その後に画像ごとに 16 バイトのディレクトリエントリが続きます。そのため、どの ICO の Base64 も AAABAA、つまりバイト 00 00 01 00 で始まります。3 つのサイズを持つアイコンの 16進ダンプを表示 の結果は次のとおりです。
00000000 00 00 01 00 03 00 10 10 00 00 00 00 20 00 56 00 |............ .V.|
00000010 00 00 36 00 00 00 20 20 00 00 00 00 20 00 6b 00 |..6... .... .k.|
00000020 00 00 8c 00 00 00 30 30 00 00 00 00 20 00 8c 00 |......00.... ...|
00000030 00 00 f7 00 00 00 89 50 4e 47 0d 0a 1a 0a 00 00 |.......PNG......|
| バイト | 値 | 意味 |
|---|---|---|
00 00 | 0 | 予約 |
01 00 | 1 | 種類:1 = アイコン、2 = カーソル |
03 00 | 3 | 画像の数 |
10 10 | 16、16 | 最初の画像の幅と高さ(00 なら 256) |
20 00 | 32 | 1 ピクセルあたりのビット数 |
56 00 00 00 | 86 | 画像データのバイト数 |
36 00 00 00 | 54 | 画像データの開始位置 |
続く 2 つのエントリは 32×32(20 20)と 48×48(30 30)を表しています。オフセット 54 から最初の画像が始まり、テキスト列の .PNG から PNG として保存されていることが分かります。
中身は PNG か BMP か
ICO 内の各画像は、完全な PNG ファイルか、通常の BM ファイルヘッダーのないビットマップのどちらかで保存されています。後者の場合、データは 28 00 00 00 で始まり、カラーピクセルの後に 1 ビットの透過マスクが続くため、ビットマップヘッダーの高さは 2 倍になっています。256×256 の大きな画像は、そのサイズの無圧縮 32 ビットビットマップが 256 KB を超えるため、たいてい PNG です。
ICO の文字列は、アイコンの見た目よりずっと長くなることがよくあります。すべてのサイズが入っていて、ビットマップのエントリは無圧縮だからです。Web サイトなら、32×32 の PNG 1 つか SVG のファビコンのほうがたいていずっと小さくなります。そうしたファイルのインライン化は ファビコンを Base64 に変換 で扱っています。
コードで画像を一覧・抽出する
次の Python 関数は、ディレクトリを読んで各画像をサイズと形式とともに返します。
import base64, struct
def ico_entries(b64: str):
data = base64.b64decode(b64.split(",", 1)[-1])
reserved, kind, count = struct.unpack_from("<HHH", data, 0)
if reserved != 0 or kind not in (1, 2):
raise ValueError("not an ICO or CUR file")
for i in range(count):
w, h, colors, _, _, bpp, size, offset = struct.unpack_from("<BBBBHHII", data, 6 + 16 * i)
image = data[offset:offset + size]
fmt = "png" if image.startswith(b"\x89PNG") else "bmp"
yield {"size": f"{w or 256}x{h or 256}", "bpp": bpp, "bytes": size, "format": fmt, "data": image}
上のアイコンなら、16x16、32x32、48x48 がすべて png として返ります。PNG のエントリの entry["data"] を .png ファイルに書き出せば、そのサイズの単独の画像になります。ビットマップのエントリは、ほかのソフトで読めるようにするにはファイルヘッダーの追加とマスクの除去が必要なので、アイコンエディターで ICO を開いてください。デコードについては Python での Base64 で詳しく解説しています。
アイコンが開けない場合
- 「これは ICO ではなく PNG のようです」。 「ファビコン」の文字列の多くは単なる PNG です。ブラウザはどんな名前でも PNG のファビコンを受け付けますが、Windows のアプリケーションリソースのように本物のアイコンファイルが必要なソフトは、名前を変えただけの PNG を受け付けません。.png としてダウンロード を使い、PNG のまま使ってください。
- 「お使いのブラウザは ICO 画像を表示できません」。 ブラウザがファイル内のどの画像も描画できませんでした。たいていは、エントリが破損している、途中で切れている、または珍しいビットマップ形式を使っているのが原因です。ダウンロードされるデータは元のままなので、アイコンエディターで開いて、どのエントリに問題があるかを確認してください。
- ブラウザでファビコンが変わらない。 ブラウザはファビコンを専用のキャッシュに保持するので、新しいアイコンはプライベートウィンドウで確認してください。
よくある質問
ICO ファイルにはいくつのサイズが入っていますか?
16進ダンプを表示 を開いて 4 バイト目と 5 バイト目を読んでください。画像の数がリトルエンディアンの数値で入っているので、03 00 なら画像は 3 つです。その後に、画像ごとに幅、高さ、ファイル内の位置を持つ 16 バイトのエントリが続きます。
プレビューに 1 つのサイズしか表示されないのはなぜですか?
ブラウザがアイコンの中から 1 つの画像を選んで描画し、寸法の行にはその画像のサイズが表示されるからです。ほかのサイズもファイル内に残っていて、一緒に保存されます。
ICO から PNG を 1 つだけ取り出せますか?
そのエントリが PNG として保存されていれば可能です。256×256 のアイコンではよくあることです。そのバイト列は完全な PNG ファイルになっていて、このページの Python スニペットで 1 つずつ保存できます。
Windows のカーソルファイルにも使えますか?
使えます。.cur ファイルは同じコンテナで、種類が 1 ではなく 2 になっているだけなので、Base64 は AAACAA で始まります。CUR と判定され、拡張子 .cur で保存されます。