在WPF中绘制像素

Jim*_*mmy 29 .net wpf

我如何管理WPF中的逐像素渲染(例如,对于光线跟踪器)?我最初的猜测是创建一个BitmapImage,修改缓冲区,并在Image控件中显示它,但我无法弄清楚如何创建一个(create方法需要一块非托管内存)

小智 38

我强烈推荐反对前两个建议.假设您使用的是3.5 SP1 ,WriteableBitmap类提供了您所需的功能.在SP1之前,除非你采取一些严肃的诡计,否则在WPF中对这个问题没有真正好的答案.

  • WriteableBitmap类从.NET 3.0开始可用,这是WPF的第一个版本.您不需要.NET 3.5来使用此类. (7认同)

Mr *_*ell 11

如果您正在考虑执行像光线跟踪器这样的事情,您需要绘制许多点,您可能需要直接在位图的内存空间中绘制,而不是通过抽象层.此代码将为您提供明显更好的渲染时间,但它需要"不安全"代码,这可能是也可能不是您的选择.


            unsafe
            {
                System.Drawing.Point point = new System.Drawing.Point(320, 240);
                IntPtr hBmp;
                Bitmap bmp = new Bitmap(640, 480);
                Rectangle lockRegion = new Rectangle(0, 0, 640, 480);
                BitmapData data = bmp.LockBits(lockRegion, ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
                byte* p;

                p = (byte*)data.Scan0 + (point.Y * data.Stride) + (point.X * 3);
                p[0] = 0; //B pixel
                p[1] = 255; //G pixel
                p[2] = 255; //R pixel

                bmp.UnlockBits(data);

                //Convert the bitmap to BitmapSource for use with WPF controls
                hBmp = bmp.GetHbitmap();
                Canvas.Source = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(hbmpCanvas, IntPtr.Zero, Int32Rect.Empty, System.Windows.Media.Imaging.BitmapSizeOptions.FromEmptyOptions());
                Canvas.Source.Freeze();
                DeleteObject(hBmp); //Clean up original bitmap
            }
Run Code Online (Sandbox Code Playgroud)

要清理hBitmap,您需要在类文件的顶部附近声明:


        [System.Runtime.InteropServices.DllImport("gdi32.dll")]
        public static extern bool DeleteObject(IntPtr hObject);
Run Code Online (Sandbox Code Playgroud)

另请注意,您需要设置项目属性以允许不安全的代码.您可以通过右键单击解决方案资源管理器中的项目并选择属性来执行此操作.转到Build选项卡.选中"允许不安全代码"框.另外我相信你需要添加对System.Drawing的引用.

  • 非常感谢这个解决方案. (2认同)

weg*_*ata 9

你可以将1X1矩形对象放在Canvas上

  private void AddPixel(double x, double y)
  {
     Rectangle rec = new Rectangle();
     Canvas.SetTop(rec, y);
     Canvas.SetLeft(rec, x);
     rec.Width = 1;
     rec.Height = 1;
     rec.Fill = new SolidColorBrush(Colors.Red);
     myCanvas.Children.Add(rec);
  }
Run Code Online (Sandbox Code Playgroud)

这应该非常接近你想要的


Ste*_*ins 8

如果需要,您可以添加小的rects,但每个都是FrameworkElement,所以它可能有点重量级.另一种选择是创建一个DrawingVisual,在其上绘制,渲染它然后将其粘贴在图像中:

private void DrawRubbish()
{
    DrawingVisual dv = new DrawingVisual();
    using (DrawingContext dc = dv.RenderOpen())
    {
        Random rand = new Random();

        for (int i = 0; i < 200; i++)
            dc.DrawRectangle(Brushes.Red, null, new Rect(rand.NextDouble() * 200, rand.NextDouble() * 200, 1, 1));

        dc.Close();
    }
    RenderTargetBitmap rtb = new RenderTargetBitmap(200, 200, 96, 96, PixelFormats.Pbgra32);
    rtb.Render(dv);
    Image img = new Image();
    img.Source = rtb;
    MainGrid.Children.Add(img);
}
Run Code Online (Sandbox Code Playgroud)