前回、作成したアイコンは背景が透過されていません。
では背景が透過されたアイコンをファイルとして保存するにはどうすればいいのでしょうか?
アイコンファイルのフォーマットは
アイコンヘッダ……ICOファイルに関する包括的情報を格納している。
ディレクトリ[1..n]……個々の画像に関する包括的情報を格納している。
アイコン画像データ[1..n]……AND/XORビットマップ形式か、PNG形式
このようになっています。
最後のAND/XORビットマップ形式は背景を透過する画像を作成することに使えます。前回のプログラムではANDビットマップをすべて0にしてしまったので背景を透過させることができませんでしたが、適切な処理をすることで背景透過のアイコンをつくることができます。
まずどのようなときに背景を透過させるかを決める必要があります。
今回はパネルの背景色がColor.FromName(“Control”)のときに背景は透明にすることにします。
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 |
List<Byte> bytes = new List<byte>(); // アイコンヘッダーを取得(前回と同じなので省略) // アイコンディレクトリを取得(前回と同じなので省略) // ビットマップヘッダーを取得(前回と同じなので省略) for(int row = 31; row >= 0; row--) { for(int colum = 0; colum < 32; colum++) { Color color = panels[colum, row].BackColor; bytes.Add(color.B); bytes.Add(color.G); bytes.Add(color.R); bytes.Add(0); if(color == Color.FromName("Control")) { // 背景を透明にするための処理 } } } for(int i = 0; i < 128; i++) { bytes.Add(?);// 背景を透明にするために適切な値をいれる } |
XORビットマップが1ピクセル4バイトであるのに対してANDビットマップは1ピクセル1ビット(8ピクセル1バイト)というのが問題をややこしくしています。
ここはこう考えます。
背景を透過にする部分をリストの格納して、ANDビットマップを設定するときにリストのなかの値に対象部分があるかどうかで判断します。
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 |
List<Byte> bytes = new List<byte>(); // アイコンヘッダーを取得(前回と同じなので省略) // アイコンディレクトリを取得(前回と同じなので省略) // ビットマップヘッダーを取得(前回と同じなので省略) List<int> vs = new List<int>(); int bit = 0; for(int row = 31; row >= 0; row--) { for(int colum = 0; colum < 32; colum++) { Color color = panels[colum, row].BackColor; bytes.Add(color.B); bytes.Add(color.G); bytes.Add(color.R); bytes.Add(0); // 以下のときは透過させる if(color == Color.FromName("Control")) { vs.Add(bit); } bit++; } } for(int i = 0; i < 128; i++) { // i * 8 + 0 i ~ i * 8 + 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); } File.WriteAllBytes("保存するファイルのパス", bytes.ToArray()); |
これで背景が透明なアイコンを保存することができるようになります。ただこのアイコンはVisualStudioのアイコンエディタでは編集できません(編集可能なのは16色のものだけ)。編集はできませんが、表示はされます。もちろん使用することも可能です。
ただアイコンは一つのファイルで複数サイズに対応できるものもあります。今回作成したものは32×32ピクセルのものだけです。複数サイズに対応するためには
アイコンヘッダ
ディレクトリ[1]
ディレクトリ[2]
ディレクトリ[n]
アイコン画像データ[1]
アイコン画像データ[2]
アイコン画像データ[n]
とすればできます。長くなるのでまた次回。