Adsense_top

2009年9月8日火曜日

C# 画像を使った変形ウインドウを作ってみた。

前回の変形ウインドウは丸いだけで面白くもないので、画像を読み込んで、その画像形状のウインドウを表示してみました。

以下のような画像を用意しました。画像の上手下手やセンスは目を瞑ってください。
マゼンタ(ピンクっぽい色)のところが透過する部分になります。

使用するクラス変数は Bitmap画像を格納する bmp だけです。
// 背景画像格納する変数
private Bitmap bmp = null;

以下が今回のメインのウインドウの形状を切り抜く部分です。
コードとしては、ひたすら透過色以外の部分の点を抜き出しているだけです
//
// 画像からウインドウの領域を作成し返します。
//
// 引数 bmp:対象画像
// 引数 transparencyKey:透過色
private Region BitmapToRegion(Bitmap bmp,
Color transparencyKey)
{
int height = bmp.Height;
int width = bmp.Width;
int xStart = 0;
System.Drawing.Drawing2D.GraphicsPath path =
new System.Drawing.Drawing2D.GraphicsPath();
// 縦方向の走査
for (int i = 0; i < height; i++)
{
// 横方向の走査
for (int j = 0; j < width; j++)
{
if (bmp.GetPixel(j, i) != transparencyKey)
{
// 透過色でない部分の連続を1ピクセル高の矩形にまとめ、
// GraphicsPathに追加していく
// (点ごとに登録処理するより効率がよいので)
xStart = j;
while ((j < width) &&
(bmp.GetPixel(j, i) != transparencyKey))
j++;
path.AddRectangle(
new Rectangle(xStart, i, j - xStart, 1));
}
}
}
// GraphicsPathからRegionを作成し返す。
Region region = new Region(path);
path.Dispose();
return region;
}

以下の部分は、まんま、画像を書いているだけです。
//
// コントロールの背景を描画。
// (OnPaintBackground をオーバーライド)
//
protected override void OnPaintBackground(PaintEventArgs e)
{
// 座標単位を設定
e.Graphics.PageUnit = GraphicsUnit.Pixel;
// 背景描画(画像を描画)
e.Graphics.DrawImage(bmp, 0, 0, bmp.Width, bmp.Height);
}

次のイベントハンドラは、枠なしのウインドウにしたので、閉じることが出来にので,クリックでとりあえず閉じられるようしているだけです。
//
// マウスクリックでウインドウを閉じる
//
private void Form1_Click(object sender, EventArgs e)
{
this.Close();
}

コンストラクタでは、ダブルバッファを使えるようにするなどの設定と、ウインドウの形状を設定しています。
クリックイベントは見て分かり易いようにココに書いているだけです。
VisualStudioのWindows フォーム デザイナに任せて勿論OKです。
//
// コンストラクタ(初期化処理)
//
public Form1()
{
InitializeComponent();
// ウインドウを閉じるためのイベントを登録
this.Click += new System.EventHandler(this.Form1_Click);

// 境界線なしにする。
this.FormBorderStyle = FormBorderStyle.None;
// 。ダブル バッファリングを使用するように動作を設定する。
this.SetStyle(ControlStyles.DoubleBuffer |
ControlStyles.UserPaint |
ControlStyles.AllPaintingInWmPaint, true);
// 画像ファイルを読み込む
bmp =(Bitmap) Bitmap.FromFile("skin.bmp");
// ウインドウサイズを調整
if (this.Width < bmp.Width)
this.Width = bmp.Width;
if (this.Height < bmp.Height)
this.Height = bmp.Height;
// ウインドウ領域を設定する。
this.Region =
BitmapToRegion(bmp, Color.FromArgb(255, 0, 255));

// 原点の色を使う場合は以下のようにする
// this.Region = BitmapToRegion(bmp, bmp.GetPixel(0, 0));
}

一番下のコメントアウトしている部分は、よく原点の色を透過色に使う方おられるので書いておきました。
で、結果以下のように表示することが出来ます。

前回の丸よりはスキンぽくなりました。画像の造りが悪くエッジが白く出ていますが...
面白くなって来たので、このシリーズ続けるかも知れません


上記メソッド「BitmapToRegion」を改良し高速化したものを「C# 画像を使った変形ウインドウの改良」としてエントリーしました。そちらも合わせてご覧ください。

1 件のコメント:

  1. for文2つとwhileの中にGetPixel()2つはものすごい時間がかかりそう。
    Byte配列で処理するように変更すれば実用性がでそうだね。

    返信削除