« Visual StudioでC#のお勉強 | トップページ | XILINXのAXI DataMoverを使う »

2019.05.09

Visual C#で点描画のやりかたを調べる

画面に点を描きたいと思います。

FPGAからデータを取得して画像を構成するようなアプリを作るイメージです。

いくつかやり方があると思うのですが、最初に試してみて遅かったのがこのやり方。

Bitmap img = new Bitmap(pictureBox3.Width, pictureBox3.Height);
for (int y=0;y< pictureBox3.Height;y++)
{
for(int x=0;x< pictureBox3.Width;x++)
{
img.SetPixel(x, y, Color.FromArgb(x & 0xff, y & 0xff , ((x >> 8) * 20) | (y >> 8) * 2));
}
}
pictureBox3.Image = img;

メモリ上にBitmapを作って(Bitmapは抽象クラスImageを継承したもの?)、Bitmapに対して点を打って、最終的にPictureBoxに転写するという方法です。

PictureBoxへの転写が遅いのではなく、SetPixelが遅いようです。

速くするにはBitmapを作るときに配列を元にして作ればよいそうで、

System.IO.MemoryStream ms = new System.IO.MemoryStream(data);

でMemoryStreamから作ればよいそうなのですが、その後、

Image img = Image.FromStream(ms);

とやっても

Bitmap img = new Bitmap(ms)

とやっても、System.ArgumentException 使用されたパラメーターが有効ではありません。と出てしまいます。

Cs4

一度作ったBitmapに対してLockBitsという関数を使って内部のデータ配列を取り出し、ポインタを使って書き込めば何とかなりました。

private void button8_Click(object sender, EventArgs e)
{
Xorshift xor = new Xorshift();
System.Drawing.Imaging.PixelFormat bmpPixelFormat = System.Drawing.Imaging.PixelFormat.Format32bppRgb;
Bitmap bmp = new Bitmap(pictureBox4.Width, pictureBox4.Height);
Rectangle rect = new Rectangle(Point.Empty, bmp.Size);
unsafe
{
System.Drawing.Imaging.BitmapData bmpData = bmp.LockBits(rect, System.Drawing.Imaging.ImageLockMode.WriteOnly, bmpPixelFormat);
IntPtr ptr = bmpData.Scan0;
int* dst = (int*)ptr.ToPointer();
for (int i = 0; i < pictureBox4.Width * pictureBox4.Height; i++)
{
*dst++ = unchecked((int)xor.Next());
}
pictureBox4.Image = bmp;
bmp.UnlockBits(bmpData);
}
}

表示された砂嵐

Cs3

ただし、unsafeで囲った上で、ビルドオプションでunsafeコードを許可しなければならないようです。

Unsafe

SetPixelを使わずにできるのはわかりましたが、unsafeをどうするかという課題が残りました。

 

|

« Visual StudioでC#のお勉強 | トップページ | XILINXのAXI DataMoverを使う »

コメント

Bitmap bmp = new Bitmap(100, 100, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
System.IO.MemoryStream ms = new System.IO.MemoryStream();
bmp.Save(ms, System.Drawing.Imaging.ImageFormat.Bmp);
byte[] buf = new byte[4 * 30];
for(int i = 0; i < 4*30; i++) {
buf[i] = 0xFF;
}
ms.Seek(1300, System.IO.SeekOrigin.Begin); // 適当
ms.Write(buf, 0, 4*30);
Bitmap img = new Bitmap(ms);
pictureBox1.Image = img;

BITMAPのヘッダーには詳しくありませんが、(何バイトシークすればいいのか不明)
ストリームへ送るときの形式が違うようです。

このコードも気持ち悪いことに変わりありませんが、どうぞ。

投稿: d | 2019.05.13 11:46

もしくはこれ


Bitmap bmp = new Bitmap(100, 100, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
System.Drawing.Imaging.PixelFormat bmpPixelFormat = System.Drawing.Imaging.PixelFormat.Format32bppRgb;
Rectangle rect = new Rectangle(Point.Empty, bmp.Size);

int[] ary = new int[100*100];
for (int i = 0; i < 100 * 100; i++)
{
ary[i] = -1;
}
System.Drawing.Imaging.BitmapData bmpData = bmp.LockBits(rect, System.Drawing.Imaging.ImageLockMode.WriteOnly, bmpPixelFormat);
IntPtr ptr = bmpData.Scan0;
Marshal.Copy(ary, 0, ptr, 100 * 100);

bmp.UnlockBits(bmpData);
pictureBox1.Image = bmp;

投稿: d | 2019.05.13 12:29

コメントを書く



(ウェブ上には掲載しません)




« Visual StudioでC#のお勉強 | トップページ | XILINXのAXI DataMoverを使う »