アイコンは一つのファイルで複数サイズに対応できます。前回作成したものは32×32ピクセルだけでしたが、複数サイズに対応させることを考えます。
アイコンヘッダ(共通)
ディレクトリ[1]
ディレクトリ[2](新しくつくる)
ディレクトリ[3](新しくつくる)
アイコン画像データ[1]
アイコン画像データ[2](新しくつくる)
アイコン画像データ[3](新しくつくる)
このようにすれば3つのサイズに対応できるアイコンを作成することができます。
16×16ピクセルのアイコンを作成しようとしてはまった件
まず32×32ピクセル以外のサイズで保存することを考えました。16×16ピクセルで保存できるかやってみることにします。
ディレクトリとビットマップヘッダーを変えればできそうです。アイコン画像データを取得するときは以下のように考えました。
異なるサイズのBitmapを作成してそこにコピーすればよい!
以下のメソッドではパネルからビットマップを作成し、これとは別に16×16ピクセルのビットマップを作成しています。
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 |
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++) srcbitmap.SetPixel(colum, row, panels[colum, row].BackColor); } Bitmap dstbitmap = new Bitmap(16, 16); Graphics g = Graphics.FromImage(dstbitmap); g.DrawImage(srcbitmap, new Rectangle(0, 0, 16, 16)); for(int row = height-1; row >= 0; row--) { for(int colum = 0; colum < width; 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.FromName("Control")) 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); // ここもまちがっているのでうまくいかない } return bytes.ToArray(); } |
保存されたファイルを開いてみると背景が透明になっていません。
パネルの色を取得するときに
1 |
if(color == Color.FromName("Control")) |
とやればその部分は色が設定されていないことがわかったのですが、Bitmapにコピーしてしまうとこの方法ではうまくいきません。
そこでパネルから色を取得するときに Color.FromName(“Control”)のときはColor.FromArgb(0)にしてコピーします。黒とColor.FromArgb(0)は同じではありません。Color.Black.ToArgb()が返す値は-16777216であり、0ではありません。
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 |
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-1; 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(); |
これで問題ないと思ったらもうひとつ問題がありました。それはANDビットマップの処理です。ビットマップは横方向1行を4byte単位のデータとしてそろえるというルールがあります。そろわない場合はパディングをしてそろえないといけません。
XORビットマップは4バイトなので気にする必要はありませんでした(4×xなら自動的に4の倍数になる)。しかしANDビットマップの場合はそうはいきません。
16ピクセルの場合、横方向1行は16ビット=2バイトになるため、残りの2バイトはパディングをいれる必要があったのです。上記のコードではうまく保存することができなかったのはパディングをいれていなかったからです。
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 |
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); } } |
このようにしないといけないのですが、そうなるとアイコンのディレクトリで設定する[対応するビットマップデータのバイト数]もビットマップヘッダー40バイト + 幅×高さ×4 + 幅×高さ÷8ではなくなってしまうので変更する必要があります。
次回はもっと汎用性のあるメソッドを作成して複数のサイズに対応できるアイコンファイルの保存方法を考えます。