Click here to Skip to main content
15,881,516 members
Articles / Programming Languages / C#
Article

WriteableBitmap in Universal Apps

Rate me:
Please Sign up or sign in to vote.
5.00/5 (4 votes)
10 Nov 2016CPOL4 min read 10.3K   5  
Small tip on how to use WriteableBitmap for Universal Apps in C#

Introduction

It seems that reading and writing pixel/color information from/to bitmaps is the most unstable thing in .NET.

Windows Forms do it in a very specific manner. WPF do it differently. Silverlight do/(did, depending on how you think about it) differently again and finally, Universal Apps, which are mostly based on WPF and Silverlight principles, do it differently again.

If you want to know, I wanted to write the Simple Life Simulation application that I already presented in one of my previous articles (Managed Bitmaps 2) as a Universal App.

I looked for the WriteableBitmap class, as that's the heart of that application. I already knew it existed in Universal apps and it actually has the same name as the classes used in Silverlight and WPF. So it was supposed to be easy. Then, I read this in the documentation in MSDN:

  • "To access the pixel content from C# or Microsoft Visual Basic, you can use the AsStream extension method to access the underlying buffer as a stream."

At that moment I was thinking "What the hell have they done this time?!?"

Then I read the next paragraph:

  • "To access the pixel content from C++, you can query for the IBufferByteAccess type (defined in Robuffer.h) and directly access its Buffer property."

In fact, that's what I was expecting to read from the start. But, is this solution C++ only? Why?

Why can't I use C# to do the same?

The Answer

Now I can tell you that I was overreacting. But the documentation is so minimal that I thought that I would only be able to use the IBufferByteAccess interface by using C++. I simply don't know why it is not exposed directly, but C# can access byte buffers/Bgra buffers directly. It needs to use unsafe code, but it is perfectly doable, and that's what I was expecting from the beginning.

To do that, all we need to do is to import the IBufferByteAccess in C# and, of course, use unsafe code to access the buffer.

The Interface

In C#, you need to import the interface like this:

C#
[ComImport]
[Guid("905a0fef-bc53-11df-8c49-001e4fc686da")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
internal unsafe interface IBufferByteAccess
{
  byte* Buffer { get; }
}

The most important thing here is not the interface itself, but all the attributes used on the interface. If you wonder, I actually got that from the C++ header.

.NET does the work of dispatching the interface to COM thanks to those attributes. So, don't think you can avoid them.

The Pixel Data

Then, considering the WriteableBitmap is always in BGRA format (where each pixel is 8 bits, that is, one byte, in that specific order, and I discovered that from the comment in the MSDN sample) I wrote this struct to represent a pixel/color:

C#
[StructLayout(LayoutKind.Sequential)]
public struct Bgra
{
  public byte B;
  public byte G;
  public byte R;
  public byte A;
}

In fact I think I could change the return type of the Buffer property from byte * to Bgra * without issues, but I preferred to keep the interface intact (as it is in C++) and then do the cast myself.

Another thing that annoyed me is that the BGRA format is called Bgra32 in WPF PixelFormats (meaning the entire BGRA uses 32 bits) while it is called Bgra8 in BitmapPixelFormat, meaning that each channel is 8 bits. In the end, they refer to the exactly same format, but the 8 in one of them is related to each channel, while the 32 in the other is related to the sum of all the 4 channels. Quite confusing, don't you think?

Using it

Finally, we get to the point of using it.

So, considering we have a writeableBitmap variable, of type WriteableBitmap, we need to the following to get the real buffer in a format we can manipulate:

C#
unsafe
{
  var pixelBuffer = writeableBitmap.PixelBuffer;	
  var bufferByteAccess = (IBufferByteAccess)pixelBuffer;
  var pixels = (Bgra *)bufferByteAccess.Buffer;
  // remaining of the code here

Then, it is a matter of chosing the pixel(s) that we want to manipulate. For example, to access an individual pixel, we use the formula (y*bitmapWidth) + x. That is: pixels[(y*bitmap.PixelWidth) + x].

But if we want to access all the pixels (either as read or write) we can do this:

C#
for(int i=0; i<width*height; i++)
{
  // Do some pixel read/manipulation here by using pixels[i]
}

Conclusion

I know, this is quite short for an article, but I simply wanted to show that the most straight forward solution, which is the one probably used in WPF and also the one used in C++, can be used in C#.

Please, if you don't have that kind of restriction, don't use a WriteableBitmap as a Stream. It may be safer (in some scenarios), but makes everything slower, much less prepared for multi-threading (in case of ray-tracing, for example) and also harder to understand.

Simple Life Simulation

Now you can find the Simple Life Simulation application on the store from this link:

Get it from Microsoft.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior) Microsoft
United States United States
I started to program computers when I was 11 years old, as a hobbyist, programming in AMOS Basic and Blitz Basic for Amiga.
At 12 I had my first try with assembler, but it was too difficult at the time. Then, in the same year, I learned C and, after learning C, I was finally able to learn assembler (for Motorola 680x0).
Not sure, but probably between 12 and 13, I started to learn C++. I always programmed "in an object oriented way", but using function pointers instead of virtual methods.

At 15 I started to learn Pascal at school and to use Delphi. At 16 I started my first internship (using Delphi). At 18 I started to work professionally using C++ and since then I've developed my programming skills as a professional developer in C++ and C#, generally creating libraries that help other developers do their work easier, faster and with less errors.

Want more info or simply want to contact me?
Take a look at: http://paulozemek.azurewebsites.net/
Or e-mail me at: paulozemek@outlook.com

Codeproject MVP 2012, 2015 & 2016
Microsoft MVP 2013-2014 (in October 2014 I started working at Microsoft, so I can't be a Microsoft MVP anymore).

Comments and Discussions

 
-- There are no messages in this forum --