ICO ファイル形式
Windows のアイコンファイル。1 つ以上の小さなラスター画像を格納します。
- MIME タイプ
- image/x-icon
- 拡張子
- .ico
- カテゴリ
- 画像
マジックナンバー(ファイル署名)
| 0x00000000 | 00000100 | ···· | reserved + type 1 (icon) |
ICO 形式について
ICO は同じアイコンを複数サイズまとめて格納するため、OS が適切なサイズを選べます。ブラウザは favicon にも使います。ヘッダは予約領域のゼロワード、画像タイプ 1、画像数と続き、そのあとに画像 1 つにつき 16 バイトのディレクトリエントリが並んで、それぞれの寸法・色深度・バイト長・ファイル内の位置を伝えます。ペイロード自体は独自の形式ではありません。ファイルヘッダを取り除いた Windows の DIB か、Windows Vista 以降なら PNG ファイルをまるごと埋め込んだもののどちらかです。つまり ICO は他の画像の山の前に置かれた小さな索引で、読むというのはまずディレクトリを読み、エントリごとに処理を振り分けることを意味します。
ヘッダーの構造(バイト単位)
| オフセット | 長さ | フィールド | 意味 |
|---|---|---|---|
| 0 | 2 | Reserved | 必ず 00 00。直後のタイプフィールドと合わせてこれがこの形式のマジックナンバーのすべてで、4 バイトのうち 2 バイトがゼロという異様に弱いものです。検出器は画像数が妥当か、最初のディレクトリエントリがファイル内を指しているかも併せて確認すべきです。 |
| 2 | 2 | Resource type | 01 00 ならアイコン、02 00 ならカーソル。.ico と .cur の違いはこの 1 バイトだけで、ヘッダもディレクトリもペイロードも他はまったく同じです。そして少し先の 2 つのフィールドが、この値によって意味を変えます。 |
| 4 | 2 | Image count | ファイル内の画像数をリトルエンディアンで表したもので、そのままこの直後に続く 16 バイトのディレクトリエントリの個数になります。favicon なら 2〜3 サイズが普通、Windows のアプリケーションアイコンなら 16 画素から 256 画素まで 6 個以上入っていることも珍しくありません。 |
| 6 | 1 | Width of the first image | 1 バイトなので表せる最大値は 255 です。Windows Vista が導入した 256 画素のアイコンは、0 を 256 と定義することで扱っています。バイトを額面どおり受け取るリーダーは幅 0 の画像を作り、たいていゼロ除算します。 |
| 7 | 1 | Height of the first image | 同じ符号化で、0 が 256 を意味する規則も同じです。DIB ヘッダと違ってこちらは本当の表示高さで、埋め込まれたビットマップが申告する 2 倍の値とは異なります。PNG 以外のエントリでは、この 2 つは設計上必ず食い違います。 |
| 8 | 1 | Palette entry count | 画像が使う色数。1 画素 8 ビット以上でパレットを持たない場合は 0 です。今どきの 32 ビットアイコンはここに必ず 0 を書きます。 |
| 9 | 1 | Reserved | 必ず 0。ファイル全体でも数少ない、解釈がまったく存在しないバイトです。だからこそ、弱い 4 バイトのマジックが本当にアイコンを意味しているか判断するときの追加チェックとして使えます。 |
| 10 | 2 | Colour planes, or cursor hotspot X | アイコンでは 0 か 1 であるべきで、リーダーは両方受け付けます。Pillow は 0 を、Windows のツール群は 1 を書きます。カーソルではこの同じ 2 バイトがホットスポットの X 座標、つまりポインタの先端とみなされる画素の位置になります。 |
| 12 | 2 | Bits per pixel, or cursor hotspot Y | リトルエンディアンの色深度で、今どき誰もが書くアルファ合成アイコンなら 32、レガシーのパレットアイコンなら 8 か 4 です。カーソルではこの 2 バイトが縦方向のホットスポット座標になり、.cur を .ico にリネームすると色深度がありえない値になるのはそのためです。 |
| 14 | 4 | Size of the image data | このエントリのペイロードのバイト長で、中身がヘッダなしの DIB でも PNG まるごとでも同じです。次のフィールドのオフセットに足せば後続画像の位置が出るので、何もデコードせずにディレクトリを歩いてファイルサイズと突き合わせられます。 |
| 18 | 4 | Offset of the image data | このエントリのペイロードがファイル先頭から数えてどこから始まるか。画像 2 つのアイコンなら 1 つ目のエントリでは 38 です。6 バイトのヘッダに 16 バイトのエントリが 2 つ。ICO のレイアウトはすべて、決め打ちではなくこのポインタから発見します。 |
| 22 | 16 | Second directory entry | エントリは詰めて並んだ配列なので、2 つ目は 22、3 つ目は 38 から、同じ 12 フィールド構成で続きます。慣習的に大きいものから並べますが強制ではなく、Windows もブラウザも順序に依存していません。 |
似た形式との見分け方
| 紛らわしい形式 | 見分け方 |
|---|---|
| PNG | 今どきの ICO は PNG ファイルをまるごと抱えていることが多いので、hex ダンプには 89 50 4E 47 0D 0A 1A 0A が現れます。ただしオフセット 0 ではありません。画像 2 つの favicon なら、たいてい最初のディレクトリエントリのオフセットフィールドが指すとおり、オフセット 38 に出てきます。結論を出す前にオフセット 0 を読んでください。00 00 01 00 なら中身がたまたま PNG のアイコン、89 50 4E 47 なら誰かが .ico と名付けた PNG です。 |
| CUR | 決め手はオフセット 2 のバイトだけです。タイプ 1 がアイコン、タイプ 2 がカーソルで、その結果オフセット 10 の 2 バイトとオフセット 12 の 2 バイトが、カラープレーンとビット深度ではなくホットスポット座標に変わります。カーソルをアイコンとして開くと 1 画素 12 ビットのような意味不明な色深度が報告されるのはそのためです。 |
| BMP | エントリのペイロードがビットマップの場合、それは正しい .bmp ファイルではありません。14 バイトの BITMAPFILEHEADER が剥がされているのでペイロードは DIB ヘッダのサイズ 28 00 00 00 から始まり、その中の高さフィールドは実際の 2 倍です。色データの後ろに同じ寸法の 1 ビット AND 透明マスクが続くためです。ペイロードを取り出して .bmp にリネームすると、縦 2 倍で絵の下にマスクがノイズとして見える画像になります。 |
| PNG/SVG favicon | バイトレベルの判定ではなく、実際に必要になる実務上の判断です。ブラウザは link rel=icon 要素経由ならどのパスに置かれた PNG や SVG でも何年も前から受け付けますし、拡張子に関係なく /favicon.ico で配られた PNG も受け付けます。今も本当に ICO コンテナを要求するのは Windows 自身、つまりエクスプローラ・タスクバー・.exe のリソースと、/favicon.ico を無条件に取りに来る非常に古いブラウザです。 |
よくある壊れ方
- ディレクトリエントリがファイル末尾より先を指している場合。画像はそれぞれ独立して到達されるので、結果は部分的になります。16 画素のアイコンは描けて 256 画素は空白になったり、どのサイズを要求したかによってあるブラウザでは favicon が出て別のブラウザでは出なかったりします。チェックは算数です。すべてのエントリでオフセット足すサイズがファイル長を超えてはいけません。
- PNG を favicon.ico にリネームしたもの。ファイル自体はどこも壊れていませんが、オフセット 0 が 00 00 01 00 ではなく 89 50 4E 47 と読めます。今のブラウザはどれも受け付けるのでウェブ上では動き、Windows やインストーラ、古いツールチェーンがアイコンリソースとして読もうとした瞬間に失敗します。
- 画像数とエントリの数が食い違っている場合。サイズを 1 つ削ったのにオフセット 4 のカウンタを減らさないツールを通すと、リーダーは最初のペイロードの 16 バイトを 13 個目のディレクトリエントリとして解析し、ありえないオフセットを持つエントリができあがります。雑なソフトウェアではエラーではなくクラッシュになります。
- 256 画素のサイズを 0 ではなく 256 と書いてしまう場合。幅も高さも 1 バイトなので、そもそも書けません。ここを間違える書き手は事故的に 0 に切り詰めてしまい、0 は 256 という規則を実装していないリーダーはサイズ 0 の画像だと報告します。同じファイルが Windows では大きなアイコンで、他の場所では不正なファイルになります。
- DIB ペイロードの AND マスクが欠けているか、サイズが違う場合。色データは問題なくデコードでき、透明部分だけがゴミになるので、それ以外は正しいアイコンの周りに黒や白の四角が出ます。雑に変換されたアイコンセットでおなじみの症状です。
この形式の現在地
ICO が今も存在する理由は、実質ひとつです。ブラウザは HTML が求めていようといまいと、いまだにサイトのルートに /favicon.ico を取りに来るので、ひとつ置いておくのがログに余計な 404 を残さず、ブックマーク一覧に何かを表示させるいちばん安上がりな方法だからです。それ以外では Windows のリソース形式で、エクスプローラのアイコン、ショートカットのアイコン、タスクバーの項目、.exe や .dll にコンパイルされたアイコンリソースはすべて同じディレクトリ+ペイロード構造を使います。ウェブの実務はすでに先へ進んでいます。link rel=icon で宣言した SVG 1 つがブラウザの欲しがるあらゆるサイズに伸縮しますし、ベクターを受け付けないプラットフォームは PNG を数枚置けば足ります。多くのサイトが今、2 サイズだけの小さな .ico をレガシー用フォールバックとして置き、本気の作業は PNG と SVG のほうに注いでいるのはそのためです。ICO にしかできないことが 1 つだけ残っています。サイズごとに本当に別の絵を束ねられることです。16 画素のアイコンが縮小版ではなく簡略化した別の絵であるべきときには、これが効いてきます。
ICO ファイルをこのサイトで開く
どれもブラウザ内で動きます。ファイルが端末から出ることはありません。
関連する形式
ICO と混同しやすい形式です。先頭バイトを見比べてください。