アイコンファイルのフォーマットは以下のようになっています。
アイコンヘッダ(共通)
ディレクトリ[1]
ディレクトリ[2](新しくつくる)
ディレクトリ[3](新しくつくる)
アイコン画像データ[1]
アイコン画像データ[2](新しくつくる)
アイコン画像データ[3](新しくつくる)
それではアイコンヘッダ、各ディレクトリ、アイコン画像データを生成するメソッドを作成してみましょう。
アイコンヘッダを生成するメソッドです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
byte[] GetIconHeader(int i) { //ヘッダ List<Byte> bytes = new List<byte>(); // 予約済み。常に0 bytes.Add(0); bytes.Add(0); // アイコン (.ico) は 1 bytes.Add(1); bytes.Add(0); // このファイルにある画像の数 bytes.Add((byte)i); bytes.Add(0); return bytes.ToArray(); } |
次にサイズが16ピクセル、32ピクセル、64ピクセルのとき、アイコンディレクトリを生成するためのメソッドを示します。
対応するビットマップデータまでのファイル内オフセットは自分で計算する必要があります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
int GetBitmapDataSize32() { return 4264; // 32 * 32 * 4 + 32 * 32 / 8 + 40; } int GetBitmapDataSize64() { return 16936; //64 * 64 * 4 + 64 * 64 / 8 + 40; } int GetBitmapDataSize16() { return 1128; //16 * 16 * 4 + 16 * 16 / 8 + 40ではないので注意 } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
byte[] GetIconDirectry16(int offset) { List<Byte> bytes = new List<byte>(); // 幅 bytes.Add(16); //高さ bytes.Add(16); //色数。256色以上なら0 bytes.Add(0); //予約済み bytes.Add(0); //カラープレーン数 bytes.Add(0); bytes.Add(0); //ICOフォーマットではピクセル毎のビット数 bytes.Add(0); bytes.Add(0); int size = GetBitmapDataSize16(); bytes.AddRange(BitConverter.GetBytes(size)); //対応するビットマップデータまでのファイル内オフセット bytes.AddRange(BitConverter.GetBytes(offset)); return bytes.ToArray(); } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
byte[] GetIconDirectry32(int offset) { List<Byte> bytes = new List<byte>(); bytes.Add(32);// 幅 bytes.Add(32);// 高さ bytes.Add(0); bytes.Add(0); bytes.Add(0); bytes.Add(0); bytes.Add(0); bytes.Add(0); int size = GetBitmapDataSize32(); bytes.AddRange(BitConverter.GetBytes(size)); // ビットマップデータの大きさ bytes.AddRange(BitConverter.GetBytes(offset)); // ビットマップデータまでのオフセット return bytes.ToArray(); } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
byte[] GetIconDirectry64(int offset) { List<Byte> bytes = new List<byte>(); bytes.Add(64);// 幅 bytes.Add(64);// 高さ bytes.Add(0); bytes.Add(0); bytes.Add(0); bytes.Add(0); bytes.Add(0); bytes.Add(0); int size = GetBitmapDataSize64(); bytes.AddRange(BitConverter.GetBytes(size)); // ビットマップデータの大きさ bytes.AddRange(BitConverter.GetBytes(offset)); // ビットマップデータまでのオフセット return bytes.ToArray(); } |
次にビットマップヘッダーを生成するメソッドです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
byte[] GetBitmapHeader16() { List<Byte> bytes = new List<byte>(); // ビットマップのヘッダーのサイズ 40 bytes.AddRange(BitConverter.GetBytes(40)); // ビットマップの幅 bytes.AddRange(BitConverter.GetBytes(16)); // ビットマップの高さ(AND/XOR操作のため倍) bytes.AddRange(BitConverter.GetBytes(16 * 2)); // planes bytes.Add(1); bytes.Add(0); //bitCount bytes.Add(32); bytes.Add(0); //compression bytes.AddRange(BitConverter.GetBytes(0)); // imageSize bytes.AddRange(BitConverter.GetBytes(0)); // xPixelsPerM bytes.AddRange(BitConverter.GetBytes(0)); // yPixelsPerM bytes.AddRange(BitConverter.GetBytes(0)); // colorUsed[4] bytes.AddRange(BitConverter.GetBytes(0)); // colorsImportant[4]; bytes.AddRange(BitConverter.GetBytes(0)); return bytes.ToArray(); } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
byte[] GetBitmapHeader32() { List<Byte> bytes = new List<byte>(); bytes.AddRange(BitConverter.GetBytes(40)); bytes.AddRange(BitConverter.GetBytes(32));// ビットマップの幅 bytes.AddRange(BitConverter.GetBytes(32 * 2));// ビットマップの高さ bytes.Add(1); bytes.Add(0); bytes.Add(32); bytes.Add(0); bytes.AddRange(BitConverter.GetBytes(0)); bytes.AddRange(BitConverter.GetBytes(0)); bytes.AddRange(BitConverter.GetBytes(0)); bytes.AddRange(BitConverter.GetBytes(0)); bytes.AddRange(BitConverter.GetBytes(0)); bytes.AddRange(BitConverter.GetBytes(0)); return bytes.ToArray(); } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
byte[] GetBitmapHeader64() { List<Byte> bytes = new List<byte>(); bytes.AddRange(BitConverter.GetBytes(40)); bytes.AddRange(BitConverter.GetBytes(64));// ビットマップの幅 bytes.AddRange(BitConverter.GetBytes(64 * 2));// ビットマップの高さ bytes.Add(1); bytes.Add(0); bytes.Add(32); bytes.Add(0); bytes.AddRange(BitConverter.GetBytes(0)); bytes.AddRange(BitConverter.GetBytes(0)); bytes.AddRange(BitConverter.GetBytes(0)); bytes.AddRange(BitConverter.GetBytes(0)); bytes.AddRange(BitConverter.GetBytes(0)); bytes.AddRange(BitConverter.GetBytes(0)); return bytes.ToArray(); } |
以下はビットマップデータを生成するメソッドです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 |
byte[] GetBitmapData16() { List<Byte> bytes = new List<byte>(); List<int> vs = new List<int>(); int bit = 0; Bitmap srcbitmap = new Bitmap(32, 32); for(int row = 0; row < 32; row++) { for(int colum = 0; colum < 32; colum++) { if(panels[colum, row].BackColor != Color.FromName("Control")) srcbitmap.SetPixel(colum, row, panels[colum, row].BackColor); else srcbitmap.SetPixel(colum, row, Color.FromArgb(0)); } } Bitmap dstbitmap = new Bitmap(16, 16); Graphics g = Graphics.FromImage(dstbitmap); g.DrawImage(srcbitmap, new Rectangle(0, 0, 16, 16)); for(int row = 15; row >= 0; row--) { for(int colum = 0; colum < 16; colum++) { Color color = dstbitmap.GetPixel(colum, row); bytes.Add(color.B); bytes.Add(color.G); bytes.Add(color.R); bytes.Add(0); // 以下のときは透過させる if(color == Color.FromArgb(0)) vs.Add(bit); bit++; } } dstbitmap.Dispose(); srcbitmap.Dispose(); int count = 16 * 16 / 8; for(int i = 0; i < count; i++) { //i~ i+7を調べる int value = 0; if(vs.Any(x => x == i * 8)) value += 128; if(vs.Any(x => x == i * 8 + 1)) value += 64; if(vs.Any(x => x == i * 8 + 2)) value += 32; if(vs.Any(x => x == i * 8 + 3)) value += 16; if(vs.Any(x => x == i * 8 + 4)) value += 8; if(vs.Any(x => x == i * 8 + 5)) value += 4; if(vs.Any(x => x == i * 8 + 6)) value += 2; if(vs.Any(x => x == i * 8 + 7)) value += 1; bytes.Add((byte)value); // パディングをいれる if(i % 2 == 1) { bytes.Add(0); bytes.Add(0); } } return bytes.ToArray(); } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 |
byte[] GetBitmapData32() { List<Byte> bytes = new List<byte>(); List<int> vs = new List<int>(); int bit = 0; Bitmap srcbitmap = new Bitmap(32, 32); for(int row = 0; row < 32; row++) { for(int colum = 0; colum < 32; colum++) { if(panels[colum, row].BackColor != Color.FromName("Control")) srcbitmap.SetPixel(colum, row, panels[colum, row].BackColor); else srcbitmap.SetPixel(colum, row, Color.FromArgb(0)); } } Bitmap dstbitmap = new Bitmap(32, 32); Graphics g = Graphics.FromImage(dstbitmap); g.DrawImage(srcbitmap, new Rectangle(0, 0, 32, 32)); for(int row = 31; row >= 0; row--) { for(int colum = 0; colum < 32; colum++) { Color color = dstbitmap.GetPixel(colum, row); bytes.Add(color.B); bytes.Add(color.G); bytes.Add(color.R); bytes.Add(0); // 以下のときは透過させる if(color == Color.FromArgb(0)) vs.Add(bit); bit++; } } dstbitmap.Dispose(); srcbitmap.Dispose(); int count = 32 * 32 / 8; for(int i = 0; i < count; i++) { int value = 0; if(vs.Any(x => x == i * 8)) value += 128; if(vs.Any(x => x == i * 8 + 1)) value += 64; if(vs.Any(x => x == i * 8 + 2)) value += 32; if(vs.Any(x => x == i * 8 + 3)) value += 16; if(vs.Any(x => x == i * 8 + 4)) value += 8; if(vs.Any(x => x == i * 8 + 5)) value += 4; if(vs.Any(x => x == i * 8 + 6)) value += 2; if(vs.Any(x => x == i * 8 + 7)) value += 1; bytes.Add((byte)value); } return bytes.ToArray(); } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 |
byte[] GetBitmapData64() { List<Byte> bytes = new List<byte>(); List<int> vs = new List<int>(); int bit = 0; Bitmap srcbitmap = new Bitmap(32, 32); for(int row = 0; row < 32; row++) { for(int colum = 0; colum < 32; colum++) { if(panels[colum, row].BackColor != Color.FromName("Control")) srcbitmap.SetPixel(colum, row, panels[colum, row].BackColor); else srcbitmap.SetPixel(colum, row, Color.FromArgb(0)); } } Bitmap dstbitmap = new Bitmap(64, 64); Graphics g = Graphics.FromImage(dstbitmap); g.DrawImage(srcbitmap, new Rectangle(0, 0, 64, 64)); for(int row = 63; row >= 0; row--) { for(int colum = 0; colum < 64; colum++) { Color color = dstbitmap.GetPixel(colum, row); bytes.Add(color.B); bytes.Add(color.G); bytes.Add(color.R); bytes.Add(0); if(color == Color.FromArgb(0)) vs.Add(bit); bit++; } } dstbitmap.Dispose(); srcbitmap.Dispose(); int count = 64 * 64 / 8; for(int i = 0; i < count; i++) { int value = 0; if(vs.Any(x => x == i * 8)) value += 128; if(vs.Any(x => x == i * 8 + 1)) value += 64; if(vs.Any(x => x == i * 8 + 2)) value += 32; if(vs.Any(x => x == i * 8 + 3)) value += 16; if(vs.Any(x => x == i * 8 + 4)) value += 8; if(vs.Any(x => x == i * 8 + 5)) value += 4; if(vs.Any(x => x == i * 8 + 6)) value += 2; if(vs.Any(x => x == i * 8 + 7)) value += 1; bytes.Add((byte)value); } return bytes.ToArray(); } |
あとはこれらをつかってファイルを保存するだけです。
以下の処理はファイル保存のためのダイアログを表示させ、指定された場所に32ピクセル、16ピクセル、64ピクセルのアイコンを保存しています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
public partial class Form1 : Form { void SaveIconFullColor() { SaveFileDialog dlg = new SaveFileDialog(); dlg.Filter = "アイコン| *.ico"; dlg.Title = "アイコンをフルカラーで保存する"; if(dlg.ShowDialog() != DialogResult.OK) return; List<Byte> bytes = new List<byte>(); byte[] header = GetIconHeader(3); byte[] directry1 = GetIconDirectry32(6 + 16 + 16 + 16); byte[] directry2 = GetIconDirectry16(6 + 16 + 16 + 16 + GetBitmapDataSize32()); byte[] directry3 = GetIconDirectry64(6 + 16 + 16 + 16 + GetBitmapDataSize32() + GetBitmapDataSize16()); byte[] bmpHeader1 = GetBitmapHeader32(); byte[] bmpHeader2 = GetBitmapHeader16(); byte[] bmpHeader3 = GetBitmapHeader64(); byte[] bmpData1 = GetBitmapData32(); byte[] bmpData2 = GetBitmapData16(); byte[] bmpData3 = GetBitmapData64(); bytes.AddRange(header); bytes.AddRange(directry1); bytes.AddRange(directry2); bytes.AddRange(directry3); bytes.AddRange(bmpHeader1); bytes.AddRange(bmpData1); bytes.AddRange(bmpHeader2); bytes.AddRange(bmpData2); bytes.AddRange(bmpHeader3); bytes.AddRange(bmpData3); File.WriteAllBytes(dlg.FileName, bytes.ToArray()); // 保存に成功したらアイコンを適用して保存先フォルダを開く Icon icon = new Icon(dlg.FileName); Icon = icon; FileInfo info = new FileInfo(dlg.FileName); System.Diagnostics.Process.Start(info.DirectoryName); } } |