- PR -

C# アルファ透過が指定されている画像をビットマップに書くと汚くなる。

投稿者投稿内容
有末 清華
ベテラン
会議室デビュー日: 2006/10/09
投稿数: 52
お住まい・勤務地: 北海道
投稿日時: 2007-02-02 00:13
UxTheme APIを使用して描画を行っています。フォームに書くと綺麗にアルファが処理されるんですがビットマップに書くとアルファが処理されずところどころ黒く残ってしまいます。

DrawIconでも同じようなことが起こったような気がしますが、アルファを綺麗に処理してビットマップに書き込むことはGDI+では可能でしょうか?または受け側がビットマップだと処理できないのでしょうか?orz

ご教授おねがいいたします。
_________________
有末 清華
crazy(){for;;{you();}} - プログラマの覚書
渋木宏明(ひどり)
ぬし
会議室デビュー日: 2004/01/14
投稿数: 1155
お住まい・勤務地: 東京
投稿日時: 2007-02-02 04:48
引用:

有末 清華さんの書き込み (2007-02-02 00:13) より:
UxTheme APIを使用して描画を行っています。フォームに書くと綺麗にアルファが処理されるんですがビットマップに書くとアルファが処理されずところどころ黒く残ってしまいます。



書き込み先の Bitmap はアルファ値をサポートしていますか?
有末 清華
ベテラン
会議室デビュー日: 2006/10/09
投稿数: 52
お住まい・勤務地: 北海道
投稿日時: 2007-02-02 17:04
書き込みBitmapはいろいろなPixcelFormat形式を試してみましたがだめでした。もちろん中にはアルファサポートの PixelFormat.Format32bppArgb などもあります。

こんな感じです

コード:

VisualStyleRenderer renderer =
new VisualStyleRenderer(className,partNumber,stateNumber);

Bitmap image = new Bitmap(panel1.DisplayRectangle.Width,
panel1.DisplayRectangle.Height,
PixelFormat.Format32bppArgb);

using(Graphics g = Graphics.FromImage(image))
{
// やってみただけ、画像の描画にはやっぱり関係ないらしい
g.CompositingMode = CompositingMode.SourceOver;
g.CompositingQuality = CompositingQuality.GammaCorrected;
// ここまで

// 描画
renderer.DrawBackground(g,panel1.DisplayRectangle);
}
// パネルに描画
e.Graphics.DrawImage(image,panel1.DisplayRectangle);



# http://www.tech-archive.net/Archive/DotNet/microsoft.public.dotnet.framework.windowsforms/2006-01/msg00237.html と同じ質問ですね。

_________________
9uiet design( http://quietdesign.rental.allinoneserver.net/ ) - タブ型デスクトップガジェット開発中。Pluginの開発してくれると嬉しいかも。

[ メッセージ編集済み 編集者: 有末 清華 編集日時 2007-02-02 17:23 ]
有末 清華
ベテラン
会議室デビュー日: 2006/10/09
投稿数: 52
お住まい・勤務地: 北海道
投稿日時: 2007-02-02 22:25
BufferedGraphics を使うことによって解決しました…がパフォーマンスが非常に悪いです。

フォームのリージョンを画像データから作成してます、透過色に指定されているいろをピクセルごとに見てリージョンに追加していく方法です。

よってBufferedGraphicsを使った際は一度ビットマップに変換してやってから書くのですがそこが遅い。

仕方がないので#ifをつかってBufferedGraphicsを使うバージョンとBitmapを使うバージョンの二つを用意することにしました。

お騒がせしました m(_ _)m
_________________
有末 清華
crazy(){for;;{you();}} - プログラマの覚書
渋木宏明(ひどり)
ぬし
会議室デビュー日: 2004/01/14
投稿数: 1155
お住まい・勤務地: 東京
投稿日時: 2007-02-03 00:16
引用:

フォームのリージョンを画像データから作成してます、透過色に指定されているいろをピクセルごとに見てリージョンに追加していく方法です。

よってBufferedGraphicsを使った際は一度ビットマップに変換してやってから書くのですがそこが遅い。



まさか GetPixel() とか使ってますか?

特に小さな画像を扱う場合を除いて、Bitmap.LockBits() してビットマップデータを直接参照する方が高速です。
有末 清華
ベテラン
会議室デビュー日: 2006/10/09
投稿数: 52
お住まい・勤務地: 北海道
投稿日時: 2007-02-03 01:07
まさかw

unsafeでまわしてます。

画像からリージョンを作るところよりもバッファからビットマップに変換するところが遅いんですよorz

backSurface.Render();

これ、かなり遅い。リージョンを作成する用の画像に一回とフォームに一回なんてやってられませんorz

Bitmapをバッファに使えばそのバッファからリージョン作成できるんで作業が一回で済みます。

っていみの遅いです。
_________________
有末 清華
crazy(){for;;{you();}} - プログラマの覚書
渋木宏明(ひどり)
ぬし
会議室デビュー日: 2004/01/14
投稿数: 1155
お住まい・勤務地: 東京
投稿日時: 2007-02-03 06:07
引用:

Bitmapをバッファに使えばそのバッファからリージョン作成できるんで作業が一回で済みます。

っていみの遅いです。



実用上問題があるほど実時間がかかってるんですか?

引用:

backSurface.Render();



は、ほとんど cpu なんか使ってないような気がするんですが。
有末 清華
ベテラン
会議室デビュー日: 2006/10/09
投稿数: 52
お住まい・勤務地: 北海道
投稿日時: 2007-02-03 11:13
僕もそう思ったんですが実際に遅いんですよね(汗。

いま作ってるのがリスト形式にアイテムを表示するフォームでマウスのホバーでアイテムを選択します。よってMouseMoveが起こったときにマウスの位置から選択されているアイテムの位置を取得して、選択されているアイテムが変わっていた場合(状態が変わっていた場合含む)描画します。

描画ではまずはバッファに書き込みます、そしてバッファからリージョンを作成して最後にプライマリに書き込みます。

アイテム数が少ない場合は問題ないのですが、10個20個になると処理が遅くマウスの動きにセレクターがついていってくれません。

コードは下記です。

コード:
/ <summary>
/// Get Selected Item Index from Point
/// </summary>
/// <param name="point"></param>
/// <returns></returns>
protected virtual int GetSelectedItemIndexFromPoint(Point point)
{
	if(shelf.ItemList.Count == 0)
		return -1;
	if(!GetBodyArea().Contains(point))
		return -1;
	
	int y = point.Y;
	if(!this.isReverseMode)
		y -= GetHeaderArea().Height;
	else
		y -= GetFooterArea().Height;
	
	y = y / shelf.ShelfListBaseTheme.ItemHeight;
	
	return y >= shelf.ItemList.Count ? -1 : y;
}

otected override void DrawBody(Graphics g)
{
	base.DrawBody(g);
				
	// Access shortcut
	int width = shelf.ShelfBaseTheme.Width;
	int height = shelf.ShelfListBaseTheme.ItemHeight;
	
	int offset = 0;
	
	for(int i=0;i<shelf.ItemList.Count;i++)
	{
		// Access shortcut
		IShelfListItem item = shelf.ItemList[i];
		ShelfListItemBaseTheme theme = GetSelectedItemTheme(i);
		
		// ItemArea
		Rectangle itemArea = new Rectangle(0,0,width,height);
		
		// Background
		Background.DirectDrawBackground(g,itemArea,theme.Background);
		
		// Icon
		g.DrawIcon(item.Icon,theme.IconArea);
		
		// Text
		Rhetoric.DrawText(g,item.Text,itemArea,theme.Text);
		
		// Incress offset
		g.TranslateTransform(0,height);
		offset += height;
	}
	g.TranslateTransform(0,-offset);
	
}

otected override void OnMouseMove(MouseEventArgs e)
{
	base.OnMouseMove(e);
	
	if(animationType != AnimationType.None)
		return;
	
	if(isOpen)
	{
		if(GetBodyArea().Contains(e.X,e.Y))
		{
			// Body
			
			#region Selecting Item Process
			if(!isDragOwner)
			{
				int selected = GetSelectedItemIndexFromPoint(new Point(e.X,e.Y));
				
				if(selected != -1)
				{
					if(e.Button == MouseButtons.Left)
						selectedItem = new SelectedItemInfo(selected,SelectedItemState.Active);
					else
						selectedItem = new SelectedItemInfo(selected,SelectedItemState.Hover);
				}
				else
					selectedItem = SelectedItemInfo.Empty;
				
				if(!previousSelectedItem.Equals(selectedItem))
				{
					// If different item is selected
					this.SetSize();
					this.Refresh();
				}
				previousSelectedItem = selectedItem;
			}
			#endregion
			
		}
	}
}

/ <summary>
/// Flip Surface
/// </summary>
public virtual void FlipSurface()
{
	FlipSurface(this.CreateGraphics());
}
public virtual void FlipSurface(Graphics g)
{
	#if(!BITMAP_DOUBLE_BUFFER)
	if(g == null)
		backSurface.Render();
	else
		backSurface.Render(g);
	#else
	g.DrawImage(backSurface,this.DisplayRectangle);
	#endif
}

public override void Refresh()
{
	Refresh(true);
}

public void Refresh(bool setregion)
{
	#if(!BITMAP_DOUBLE_BUFFER)
	Refresh(setregion,null);
	#else
	Refresh(setregion,this.CreateGraphics());
	#endif
}
public void Refresh(bool setregion,Graphics g)
{		
	#if(!BITMAP_DOUBLE_BUFFER)
	DrawOnSurface(backSurface.Graphics);
	#else
	using(Graphics grfx = Graphics.FromImage(backSurface))
		DrawOnSurface(grfx);
	#endif
	if(setregion)
		SetRegion();
	FlipSurface(g);
}

/// <summary>
/// SetRegion
/// </summary>
/// <description>Create Region from BackSurface and Form.TransparencyKey</description>
public void SetRegion()
{
	#if(!BITMAP_DOUBLE_BUFFER)
	Bitmap surface = new Bitmap(this.Width,this.Height);
	this.DrawToBitmap(surface,this.ClientRectangle);
	SetRegion(surface);
	#else
	SetRegion(backSurface);
	#endif
}
public virtual void SetRegion(Bitmap surface)
{
	this.Region = 
		WidgetHelper.CreateRegionFromBitmap(surface,this.TransparencyKey);
}




こういうのパフォーマンスが悪いと使っててイライラしますからねぇorz
_________________
有末 清華
crazy(){for;;{you();}} - プログラマの覚書

スキルアップ/キャリアアップ(JOB@IT)