Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Drawing Pixels in WPF

Tags:

.net

wpf

I highly recommend against the previous two suggestions. The WriteableBitmap class provides what you need assuming you are using 3.5 SP1. Before SP1 there's no really good answer to this question in WPF unless you resort to some serious trickery.


If you are thinking of doing something like a ray tracer where you will need to be plotting lots of points you will probably want to draw in the bitmap's memory space directly instead of through the layers of abstraction. This code will give you significantly better render times, but it comes at the cost of needing "unsafe" code, which may or may not be an option for you.


            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
            }

To clean up the hBitmap you will need to declare this near the top of your class file:


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

Also note that you will need to set the project properties to allow unsafe code. You can do this by right clicking on the project in solution explorer and selecting properties. Goto the Build tab. Check the "Allow unsafe code" box. Also I believe you will need to add a reference to System.Drawing.


You can add small rects if you want, but each of those is a FrameworkElement, so it's probably a bit heavyweight. The other option is to create yourself a DrawingVisual, draw on it, render it then stick it in an image:

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);
}

you could place 1X1 Rectangle objects onto a 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);
  }

That should be pretty close to what you want