8bitsデータを WriteableBitmap に書き込む

WindowsForms アプリケーションでは、画像データなどの 8, 24, 32ビットデータをウインドウに表示するには Bitmap というクラスを仲介してそれを実現していました。

しかし Bitmap に byte[] などの画像データを高速に仕込むには unsafe で囲んで、書き込む画像データを fixed して、ビットマップを LockBitsして、画像データをコピーして、UnlockBits で戻して、いろいろと手続きが多く煩雑なものでした。

さすがにそれはないよねぇ、とマイクロソフトが思ったのでしょうか、System.Windows.Media.Imaging のネームスペースで WriteableBitmap という便利なクラスを提供してくれるようになりました。ほんとうにありがたいですね。

8bits のグラデーションデータ

下記の名前空間の追加をお忘れなく.
using System.Windows.Media;
using System.Windows.Media.Imaging;

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Navigation;
using System.Windows.Shapes;

// この using 追加を忘れずに. Don't forget to add this sentence.
using System.Windows.Media;
using System.Windows.Media.Imaging;

namespace aaa
{

	public partial class MainWindow : Window
	{

		const int INI_W = 512;
		const int INI_H = 256;

		// 表示したいデータ.
		byte [] Data000;

		// 表示したいデータを内包させるビットマップ.
		WriteableBitmap Bmp000;

		public MainWindow()
		{
			InitializeComponent();

		}

		private void menuDebugExec000_Click( object sender, RoutedEventArgs e )
		{

			// データ領域を確保する.
			int w = INI_W;
			int h = INI_H;
			int numpix = w * h;
			Data000 = new byte[ numpix ];

			// データ領域に上が黒くて下が白いグラデーションを格納する.
			for ( int j = 0; j < h; j++ )
			{
				int adrs = w * j;
				for ( int i = 0; i < w; i++ )
				{
					Data000[ adrs ] = (byte)(j);
					adrs++;
				}
			}

			// ビットマップのDPI、とりあえず 96dpi で決め打ちした.
			const double DPI_X = 96.0;
			const double DPI_Y = 96.0;

			// byte[] データを表示するのでグレースケールな256要素のカラーパレット形式とする.
			PixelFormat pixfmt = PixelFormats.Indexed8;

			// 256要素のカラーパレット生成のために必要な256要素の色リストを作成する.
			List<Color> list_colors = new List<Color>(0);
			const int NUM_COLORS = 256;
			for ( int k = 0; k < NUM_COLORS; k++ )
			{
				const byte LEVEL_ALPHA = 0xff;
				byte level = (byte)( k );
				Color c = Color.FromArgb( LEVEL_ALPHA, level, level, level );
				list_colors.Add( c );
			}

			// 256要素の色リストからパレットを生成する.
			BitmapPalette palette = new BitmapPalette( list_colors );

			// 書き込み可能なビットマップを作成する.
			Bmp000 = new WriteableBitmap( w, h, DPI_X, DPI_Y, pixfmt, palette );

			// 書き込み可能ビットマップにデータを仕込む.
			Int32Rect rct = new Int32Rect( 0, 0, w, h );
			int stride_bytes = w * sizeof( byte );
			const int OFFSET_BYTES = 0;
			Bmp000.WritePixels( rct, Data000, stride_bytes, OFFSET_BYTES );

			// 表示させるデータを内包したビットマップをGUI表示する.
			image000.Width = w;
			image000.Height = h;
			image000.Source = Bmp000;

		}

	}
}

実行結果はこんな感じです。87行目にある WritePixels というメソッド1行だけです。unsafe なども不要です。ありがたい。

WindowsForms のときの実行コードを確認して比較するには下記の記事を参照してください。unsafe, fixed, LockBits, UnlockBits いろいろ大変です。

8bitsデータをビットマップに書き込む

byte[] で定義された256階調のグレースケールデータを Bitmap に格納する方法を紹介します。

本記事に紹介したコードは xaml で画像出力コントロールとして image000 が定義されている前提のコードです。下記の記事に示した xaml をご覧ください。

オーソドックスなウインドウスタイルを実現する(非MVVM) | GazoYaro

MFC や WindowsForms で作成したようなオーソドックスな GUI のウインドウを XAML で定義する方法を紹介します。