.ico decompiler
by sii_side
HTML
<input type="file" id="ico">
<h1>Canvasで読み込み(1つだけ)</h1>
<canvas id="c" width="300" height="300"></canvas>
<h1>imgで読み込み(全部)</h1>
<div id="op"></div>
CSS
body {
background-color: #999;
}
JavaScript
var ipt = document.querySelector("#ico");
ipt.addEventListener("change", function() {
/*--------------------
.icoファイルを読み込んで解析する
--------------------*/
var ico = ipt.files[0];
var fr = new FileReader();
fr.addEventListener("load", function() {
var u = new Uint8Array(fr.result);
var num = u[4];
//5バイト目:.icoに含まれるアイコンの数
var mIcon = [];
/*
icon解析用オブジェクト
[
{
header: (IconInfoHeader),
icon : {
header: (BitmapInfoHeader),
imageData: (画像データ)
}
}, ...
]
*/
for(var i = 0; i < num; i++) {
var hStart = 6 + i * 16;
//各IconInfoHeaderの始点(.ico先頭7バイト目から16バイト単位で続く)
var iconObj = {};
iconObj.header = {};
iconObj.header.binary = u.slice(hStart, hStart + 16);
iconObj.header.width = u[hStart ] || 256;
iconObj.header.height = u[hStart + 1] || 256;
iconObj.header.icoDIBSize = u[hStart + 8] + u[hStart + 9] * 256 + u[hStart + 10] * 256 * 256 + + u[hStart + 11] * 256 * 256 * 256;
//IconInfoHeader09-12バイト目:サイズ(容量)
iconObj.header.icoDIBOffset = u[hStart + 12] + u[hStart + 13] * 256 + u[hStart + 14] * 256 * 256 + + u[hStart + 15] * 256 * 256 * 256;
//IconInfoHeader13-16バイト目:位置(.icoファイル内でアイコンのデータ(ヘッダ含む)が何バイト目から始まっているか)
iconObj.icon = {};
iconObj.icon.binary = u.slice(iconObj.header.icoDIBOffset, iconObj.header.icoDIBOffset + iconObj.header.icoDIBSize);
iconObj.icon.header = u.slice(iconObj.header.icoDIBOffset, iconObj.header.icoDIBOffset + 40);
//BitmapInfoHeader(とりあえず使わないのでUint8Arrayのまま)
iconObj.icon.imageData = u.slice(iconObj.header.icoDIBOffset + 40, iconObj.header.icoDIBOffset + 40 + iconObj.header.width * iconObj.header.height * 4);
//ImageData(MaskDataは無視)
//(得られるバイナリはRGBAではなくBGRAの順(エンディアンの関係?))
mIcon.push(iconObj);
}
//サイズ順にソート(降順なので先頭が最大)
//(バイト数で比較しているので必ずしも解像度順とは限らない)
...