WPF中的位图绘制

时间:2016-12-30 13:58:52

标签: c# wpf winforms bitmap

我有一些用C#编写的小型WinForms应用程序,它们利用System.Drawing.BitmapSystem.Windows.Forms.PictureBox显示应用程序随时间维护的原始字节缓冲区的位图。在某种程度上,它类似于穷人的动画。

我想将这些应用程序移植到WPF,但在字节缓冲区写入中有很多自定义逻辑,我不愿意改变。经过一些谷歌搜索,我尝试使用System.Windows.Media.Imaging.WriteableBitmap类,但无法使其工作。如何使用这个类并且它是否适合我的原始设计?

这是来自原始WinForms应用程序的片段,它累积地将随机颜色写入位图上的随机位置:

private void Form1_Load(object sender, EventArgs e)
{
    _timer.Tick += new EventHandler(Timer_Tick);
    _timer.Interval = 25;
    _timer.Enabled = true;
}

private void Timer_Tick(object sender, EventArgs e)
{
    Animate();
}

private void Animate()
{
    Bitmap bitmap = (Bitmap)pictureBox1.Image;

    if (bitmap != null)
    {
        bitmap.Dispose();
    }

    bitmap = new Bitmap(pictureBox1.Width, pictureBox1.Height);

    var data = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb);

    if (_buffer == null)
    {
        _buffer = new byte[data.Stride * bitmap.Height];
    }

    for (int i = 0; i < 1000; i++)
    {
        var x = _random.Next(bitmap.Width);
        var y = _random.Next(bitmap.Height);

        var red = (byte)_random.Next(byte.MaxValue);
        var green = (byte)_random.Next(byte.MaxValue);
        var blue = (byte)_random.Next(byte.MaxValue);
        var alpha = (byte)_random.Next(byte.MaxValue);

        _buffer[y * data.Stride + x * 4] = blue;
        _buffer[y * data.Stride + x * 4 + 1] = green;
        _buffer[y * data.Stride + x * 4 + 2] = red;
        _buffer[y * data.Stride + x * 4 + 3] = alpha;
    }

    Marshal.Copy(_buffer, 0, data.Scan0, _buffer.Length);

    bitmap.UnlockBits(data);

    pictureBox1.Image = bitmap;
}

1 个答案:

答案 0 :(得分:3)

如果您已经有现有代码,我认为最简单,最快(尽管处理速度最快)可能是维护代码并在需要显示图像时转换为BitmapSource:

  BitmapImage bmpImage = new BitmapImage();
  MemoryStream stream = new MemoryStream();
  bitmap.Save(stream, ImageFormat.MemoryBmp);
  bmpImage.BeginInit();
  bmpImage.StreamSource = stream;
  bmpImage.EndInit();
  bmpImage.Freeze();

  return bmpImage;

另一个选项是使用WritableBitmap,它可以提高效率,但可能需要您移植更多代码。您可以使用与Bitmap对象相同的方式创建WritableBitmap,并且可以访问其原始后备缓冲区(和IntPtr),并且可以根据需要操作图像数据。此链接应该为您提供有关WritableBitmap的所有信息: WriteableBitmap

以下是您的案例示例(请注意您需要知道您的dpi):

      WriteableBitmap bitmap = new WriteableBitmap(pictureBox1.Width, pictureBox1.Height, dpi, dpi, PixelFormats.Bgra32, null);

  if (_buffer == null)
  {
    _buffer = new byte[bitmap.BackBufferStride * pictureBox1.Height];
  }

  for (int i = 0; i < 1000; i++)
  {
    var x = _random.Next(bitmap.Width);
    var y = _random.Next(bitmap.Height);

    var red = (byte)_random.Next(byte.MaxValue);
    var green = (byte)_random.Next(byte.MaxValue);
    var blue = (byte)_random.Next(byte.MaxValue);
    var alpha = (byte)_random.Next(byte.MaxValue);

    _buffer[y * bitmap.BackBufferStride + x * 4] = blue;
    _buffer[y * bitmap.BackBufferStride + x * 4 + 1] = green;
    _buffer[y * bitmap.BackBufferStride + x * 4 + 2] = red;
    _buffer[y * bitmap.BackBufferStride + x * 4 + 3] = alpha;
  }

  bitmap.WritePixels(new System.Windows.Int32Rect(0, 0, bitmap.PixelWidth, bitmap.PixelHeight),
      _buffer, bitmap.PixelWidth * bitmap.Format.BitsPerPixel / 8, 0);