Set the pixels in a WPF bitmap in C#

[WPF bitmap]

This example shows how you can manipulate the pixels in a WPF bitmap.

One of the things I like least about WPF is the way Microsoft threw away everything we had learned over years of working with Visual Studio. Yes, it’s okay to start moving in a new direction, but there’s no reason to ignore lessons learned through years of hard experience. Working with bitmapped images is one of the areas where WPF did just that. The .NET tools aren’t great for manipulating the pixels in an image, but they’re better than the one (note I don’t say “ones”) provided by WPF.

Anyway, to create a bitmapped image in WPF, you build a WriteableBitmap object. You then create a one-dimensional array holding the raw pixel information for the image, and you use the bitmap’s WritePixels method to copy the pixel data into the image. The following code shows how this program does it.

private void Window_Loaded(object sender, RoutedEventArgs e)
{
    const int width = 240;
    const int height = 240;

    WriteableBitmap wbitmap = new WriteableBitmap(
        width, height, 96, 96, PixelFormats.Bgra32, null);
    byte[, ,] pixels = new byte[height, width, 4];

    // Clear to black.
    for (int row = 0; row < height; row++)
    {
        for (int col = 0; col < width; col++)
        {
            for (int i = 0; i < 3; i++)
                pixels[row, col, i] = 0;
            pixels[row, col, 3] = 255;
        }
    }

    // Blue.
    for (int row = 0; row < 80; row++)
    {
        for (int col = 0; col <= row; col++)
        {
            pixels[row, col, 0] = 255;
        }
    }

    // Green.
    for (int row = 80; row < 160; row++)
    {
        for (int col = 0; col < 80; col++)
        {
            pixels[row, col, 1] = 255;
        }
    }

    // Red.
    for (int row = 160; row < 240; row++)
    {
        for (int col = 0; col < 80; col++)
        {
            pixels[row, col, 2] = 255;
        }
    }

    // Copy the data into a one-dimensional array.
    byte[] pixels1d = new byte[height * width * 4];
    int index = 0;
    for (int row = 0; row < height; row++)
    {
        for (int col = 0; col < width; col++)
        {
            for (int i = 0; i < 4; i++)
                pixels1d[index++]= pixels[row, col, i];
        }
    }

    // Update writeable bitmap with the colorArray to the image.
    Int32Rect rect = new Int32Rect(0, 0, width, height);
    int stride = 4 * width;
    wbitmap.WritePixels(rect, pixels1d, stride, 0);

    // Create an Image to display the bitmap.
    Image image = new Image();
    image.Stretch = Stretch.None;
    image.Margin = new Thickness(0);

    grdMain.Children.Add(image);

    //Set the Image source.
    image.Source = wbitmap;
}

The code starts by creating the WriteableBitmap. It sets the bitmap’s resolution to 96 pixels per inch and uses the Bgra32 format so the bitmap uses 32 bits per pixel to represent blue, green, red, and alpha (opacity) information.

Note the order: blue, green, red, alpha. That’s the order in which the data is stored for each pixel. It’s probably not the order you would expect.

Next, to make working with the pixel data easier, the program makes a three-dimensional array of bytes. Each pixel’s row and column contains 4 bytes in the array to hold its blue, green, red, and alpha components.

The code then uses several loops to set the pixel byte data. It first sets each pixel’s color components to 0 and its alpha components to 255 (opaque). It then uses three loops to create areas of blue, green, and red.

The bitmap’s WritePixels method expects a one-dimensional array as a parameter, so the code copies the three-dimensional data into a one-dimensional array.

Next the program calls the bitmap’s WritePixels method to copy the pixel data into the bitmap. The rectangle indicates the part of the bitmap to update. The stride parameter tells the WritePixels method how many bytes of data there are per row in the bitmap. This is simply the bitmap’s width in pixels times the number of bytes per pixel. The final parameter is the offset in the array to the spot where the data to be copied begins.

At this point, the bitmap is ready to use. The program creates an Image control to display it, adds the Image to the program’s main Grid control, and displays the bitmap in the Image control’s Source property.

The process is cumbersome and non-intuitive, but manageable once you know the steps. It shouldn’t be too hard to copy and paste this code to manipulate bitmaps in the future.


Download Example   Follow me on Twitter   RSS feed   Donate




This entry was posted in graphics, image processing, wpf, XAML and tagged , , , , , , , , , , , , , . Bookmark the permalink.

4 Responses to Set the pixels in a WPF bitmap in C#

  1. Make a BitmapPixelMaker class to make working with pixels in a WriteableBitmap easier using WPF and C#

    After building the example Set the pixels in a bitmap using WPF, XAML, and C#, I couldn’t get it out of my head. Doing the math to set the correct bytes in a one-dimensional pixel array isn’t all that hard, but it is annoying and I don’t see why Microsoft had to make it so unfriendly. So I decided to make it a bit friendlier. This example uses a BitmapPixelMaker class to represent a one-dimensional array that will be used to make a WriteableBitmap object. It only supports the Bgra32 format, but you could write similar classes …

  2. Ello says:

    Opinions on Windows 10 and things to expect as a C# developer?

  3. alok says:

    can i fill the custom colors in it?
    like some color other than RGB

    • RodStephens says:

      I think you’re asking whether you can use colors other than pure red, green, and blue. Yes you can. Just set the red, green, blue, and alpha components as in the following code.

      for (int row = 160; row < 240; row++)
      {
          for (int col = 0; col < 80; col++)
          {
              // Light sky blue 135, 206, 250
              pixels[row, col, 0] = 250;  // Blue
              pixels[row, col, 1] = 206;  // Green
              pixels[row, col, 2] = 135;  // Red
              pixels[row, col, 3] = 255;  // Alpha
          }
      }

Leave a Reply

Your email address will not be published. Required fields are marked *